diff options
author | Ivan Chen <ivan@tagg.id> | 2021-06-24 17:41:45 -0400 |
---|---|---|
committer | Ivan Chen <ivan@tagg.id> | 2021-06-24 17:41:45 -0400 |
commit | b184179a8bff25ad018d02abc31acadc7b3f6a62 (patch) | |
tree | efd94448ee76860156d7622a61e6eb8785c10f10 /src/components/comments/ZoomInCropper.tsx | |
parent | 981051448fee6197544383e535fea7a72827d41d (diff) | |
parent | 53bdc94cf0491e348b7d4ad61e51ce1844423773 (diff) |
Merge branch 'master' into tma948-video-playback
# Conflicts:
# ios/Podfile.lock
# package.json
# src/components/moments/Moment.tsx
# src/routes/main/MainStackNavigator.tsx
# src/screens/moments/TagFriendsScreen.tsx
# src/screens/profile/CaptionScreen.tsx
# yarn.lock
Diffstat (limited to 'src/components/comments/ZoomInCropper.tsx')
-rw-r--r-- | src/components/comments/ZoomInCropper.tsx | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/components/comments/ZoomInCropper.tsx b/src/components/comments/ZoomInCropper.tsx new file mode 100644 index 00000000..bca4e599 --- /dev/null +++ b/src/components/comments/ZoomInCropper.tsx @@ -0,0 +1,201 @@ +import {RouteProp} from '@react-navigation/core'; +import {useFocusEffect} from '@react-navigation/native'; +import {StackNavigationProp} from '@react-navigation/stack'; +import {default as React, useCallback, useEffect, useState} from 'react'; +import {Image, StyleSheet, TouchableOpacity} from 'react-native'; +import {normalize} from 'react-native-elements'; +import ImageZoom, {IOnMove} from 'react-native-image-pan-zoom'; +import PhotoManipulator from 'react-native-photo-manipulator'; +import CloseIcon from '../../assets/ionicons/close-outline.svg'; +import {MainStackParams} from '../../routes'; +import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import {TaggSquareButton} from '../common'; + +type ZoomInCropperRouteProps = RouteProp<MainStackParams, 'ZoomInCropper'>; +type ZoomInCropperNavigationProps = StackNavigationProp< + MainStackParams, + 'ZoomInCropper' +>; +interface ZoomInCropperProps { + route: ZoomInCropperRouteProps; + navigation: ZoomInCropperNavigationProps; +} + +export const ZoomInCropper: React.FC<ZoomInCropperProps> = ({ + route, + navigation, +}) => { + const {screenType, title, media} = route.params; + const [aspectRatio, setAspectRatio] = useState<number>(1); + + // Stores the coordinates of the cropped image + const [x0, setX0] = useState<number>(); + const [x1, setX1] = useState<number>(); + const [y0, setY0] = useState<number>(); + const [y1, setY1] = useState<number>(); + + // Removes bottom navigation bar on current screen and add it back when navigating away + useFocusEffect( + useCallback(() => { + navigation.dangerouslyGetParent()?.setOptions({ + tabBarVisible: false, + }); + return () => { + navigation.dangerouslyGetParent()?.setOptions({ + tabBarVisible: true, + }); + }; + }, [navigation]), + ); + + // Setting original aspect ratio of image + useEffect(() => { + if (media.uri) { + Image.getSize( + media.uri, + (w, h) => { + setAspectRatio(w / h); + }, + (err) => console.log(err), + ); + } + }, []); + + // Crops original image based of (x0, y0) and (x1, y1) coordinates + const handleNext = () => { + if ( + x0 !== undefined && + x1 !== undefined && + y0 !== undefined && + y1 !== undefined + ) { + PhotoManipulator.crop(media.uri, { + x: x0, + y: y1, + width: Math.abs(x0 - x1), + height: Math.abs(y0 - y1), + }) + .then((croppedURL) => { + navigation.navigate('CaptionScreen', { + screenType, + title: title, + media: { + filename: media.filename, + uri: croppedURL, + isVideo: false, + }, + }); + }) + .catch((err) => console.log('err: ', err)); + } else if ( + x0 === undefined && + x1 === undefined && + y0 === undefined && + y1 === undefined + ) { + navigation.navigate('CaptionScreen', { + screenType, + title: title, + media, + }); + } + }; + + /* Records (x0, y0) and (x1, y1) coordinates used later for cropping, + * based on(x, y) - the center of the image and scale of zoom + */ + const onMove = (position: IOnMove) => { + Image.getSize( + media.uri, + (w, h) => { + const x = position.positionX; + const y = position.positionY; + const scale = position.scale; + const screen_ratio = SCREEN_HEIGHT / SCREEN_WIDTH; + let tempx0 = w / 2 - x * (w / SCREEN_WIDTH) - w / 2 / scale; + let tempx1 = w / 2 - x * (w / SCREEN_WIDTH) + w / 2 / scale; + if (tempx0 < 0) { + tempx0 = 0; + } + if (tempx1 > w) { + tempx1 = w; + } + const x_distance = Math.abs(tempx1 - tempx0); + const y_distance = screen_ratio * x_distance; + let tempy0 = h / 2 - y * (h / SCREEN_HEIGHT) + y_distance / 2; + let tempy1 = h / 2 - y * (h / SCREEN_HEIGHT) - y_distance / 2; + if (tempy0 > h) { + tempy0 = h; + } + if (tempy1 < 0) { + tempy1 = 0; + } + setX0(tempx0); + setX1(tempx1); + setY0(tempy0); + setY1(tempy1); + }, + (err) => console.log(err), + ); + }; + + return ( + <> + <TouchableOpacity + style={styles.closeButton} + onPress={() => navigation.goBack()}> + <CloseIcon height={25} width={25} color={'white'} /> + </TouchableOpacity> + <ImageZoom + style={styles.zoomView} + cropWidth={SCREEN_WIDTH} + cropHeight={SCREEN_HEIGHT} + imageWidth={SCREEN_WIDTH} + imageHeight={SCREEN_WIDTH / aspectRatio} + onMove={onMove}> + <Image + style={{width: SCREEN_WIDTH, height: SCREEN_WIDTH / aspectRatio}} + source={{ + uri: media.uri, + }} + /> + </ImageZoom> + <TaggSquareButton + onPress={handleNext} + title={'Next'} + buttonStyle={'normal'} + buttonColor={'blue'} + labelColor={'white'} + style={styles.button} + labelStyle={styles.buttonLabel} + /> + </> + ); +}; + +const styles = StyleSheet.create({ + closeButton: { + position: 'absolute', + top: 0, + paddingTop: HeaderHeight, + zIndex: 1, + marginLeft: '5%', + }, + button: { + zIndex: 1, + position: 'absolute', + bottom: normalize(20), + right: normalize(15), + width: normalize(108), + height: normalize(25), + borderRadius: 10, + }, + buttonLabel: { + fontWeight: '700', + fontSize: normalize(15), + lineHeight: normalize(17.8), + letterSpacing: normalize(1.3), + textAlign: 'center', + }, + zoomView: {backgroundColor: 'black'}, +}); |