2021-01-01 17:52:14 +01:00
|
|
|
import { StyleConstants } from '@utils/styles/constants'
|
|
|
|
import { useTheme } from '@utils/styles/ThemeManager'
|
2021-01-04 10:50:24 +01:00
|
|
|
import React, { MutableRefObject, useContext } from 'react'
|
2021-01-19 01:13:45 +01:00
|
|
|
import { useTranslation } from 'react-i18next'
|
2021-01-04 10:50:24 +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'
|
2021-01-04 10:50:24 +01:00
|
|
|
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
|
|
|
|
focus: MutableRefObject<{
|
|
|
|
x: number
|
|
|
|
y: number
|
|
|
|
}>
|
|
|
|
}
|
|
|
|
|
|
|
|
const ComposeEditAttachmentImage: React.FC<Props> = ({ index, focus }) => {
|
2021-01-19 01:13:45 +01:00
|
|
|
const { t } = useTranslation('sharedCompose')
|
2020-12-30 00:56:25 +01:00
|
|
|
const { theme } = useTheme()
|
|
|
|
|
|
|
|
const { composeState } = useContext(ComposeContext)
|
2021-01-22 01:34:20 +01:00
|
|
|
const theAttachmentRemote = composeState.attachments.uploads[index].remote
|
|
|
|
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-01-22 01:34:20 +01:00
|
|
|
((theAttachmentRemote as Mastodon.AttachmentImage).meta?.original
|
|
|
|
?.aspect || 1)
|
2020-12-30 00:56:25 +01:00
|
|
|
}
|
|
|
|
|
2021-01-04 10:50:24 +01:00
|
|
|
const panX = useSharedValue(
|
|
|
|
(((theAttachmentRemote as Mastodon.AttachmentImage).meta?.focus?.x || 0) *
|
|
|
|
imageDimensionis.width) /
|
|
|
|
2
|
|
|
|
)
|
|
|
|
const panY = useSharedValue(
|
|
|
|
(((theAttachmentRemote as Mastodon.AttachmentImage).meta?.focus?.y || 0) *
|
|
|
|
imageDimensionis.height) /
|
|
|
|
2
|
|
|
|
)
|
|
|
|
const updateFocus = ({ x, y }: { x: number; y: number }) => {
|
|
|
|
focus.current = { x, y }
|
|
|
|
}
|
|
|
|
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
|
|
|
})
|
2021-01-04 10:50:24 +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
|
|
|
|
],
|
2021-01-04 10:50:24 +01:00
|
|
|
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-01-04 14:55:34 +01:00
|
|
|
<View style={{ overflow: 'hidden', flex: 1, alignItems: 'center' }}>
|
2020-12-30 00:56:25 +01:00
|
|
|
<Image
|
|
|
|
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
|
|
|
}}
|
|
|
|
/>
|
2021-01-04 10:50:24 +01:00
|
|
|
<PanGestureHandler onGestureEvent={onGestureEvent}>
|
2020-12-30 00:56:25 +01:00
|
|
|
<Animated.View
|
|
|
|
style={[
|
2021-01-04 10:50:24 +01:00
|
|
|
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'
|
2020-12-30 00:56:25 +01:00
|
|
|
fill={theme.backgroundOverlay}
|
|
|
|
/>
|
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.primary }]}>
|
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({
|
|
|
|
imageFocusText: {
|
|
|
|
...StyleConstants.FontStyle.M,
|
|
|
|
padding: StyleConstants.Spacing.Global.PagePadding
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
export default ComposeEditAttachmentImage
|