aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Chen <ivan@tagg.id>2021-06-23 17:50:22 -0400
committerGitHub <noreply@github.com>2021-06-23 17:50:22 -0400
commit53bdc94cf0491e348b7d4ad61e51ce1844423773 (patch)
tree5cc31490ed3d276e51cb1dc4385c2b26e6071ff9
parent53461e8412b1f3b95124f9d9a6f50580d26930f5 (diff)
parentd309c8e66470d8d89063b817397cd6568bf6a8bf (diff)
Merge pull request #469 from shravyaramesh/tma923-image-cropper
[TMA-923/924] Image cropper, Display arbitrary sized image
-rw-r--r--ios/Podfile2
-rw-r--r--ios/Podfile.lock36
-rw-r--r--package.json5
-rw-r--r--src/components/comments/CommentsCount.tsx48
-rw-r--r--src/components/comments/ZoomInCropper.tsx199
-rw-r--r--src/components/common/MomentTags.tsx28
-rw-r--r--src/components/moments/IndividualMomentTitleBar.tsx58
-rw-r--r--src/components/moments/Moment.tsx10
-rw-r--r--src/components/moments/MomentPost.tsx347
-rw-r--r--src/components/moments/MomentPostHeader.tsx116
-rw-r--r--src/components/moments/index.ts2
-rw-r--r--src/components/moments/legacy/MomentPostContent.tsx (renamed from src/components/moments/MomentPostContent.tsx)19
-rw-r--r--src/components/profile/MomentMoreInfoDrawer.tsx8
-rw-r--r--src/components/profile/PublicProfile.tsx4
-rw-r--r--src/routes/main/MainStackNavigator.tsx10
-rw-r--r--src/routes/main/MainStackScreen.tsx9
-rw-r--r--src/screens/main/NotificationsScreen.tsx5
-rw-r--r--src/screens/moments/TagFriendsScreen.tsx46
-rw-r--r--src/screens/onboarding/BasicInfoOnboarding.tsx5
-rw-r--r--src/screens/profile/CaptionScreen.tsx2
-rw-r--r--src/screens/profile/IndividualMoment.tsx88
-rw-r--r--yarn.lock29
22 files changed, 768 insertions, 308 deletions
diff --git a/ios/Podfile b/ios/Podfile
index 4eca4100..d8324a6d 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -33,4 +33,4 @@ end
# add the Firebase pod for Google Analytics
pod 'Firebase/Analytics'
# add pods for any other desired Firebase products
-# https://firebase.google.com/docs/ios/setup#available-pods \ No newline at end of file
+# https://firebase.google.com/docs/ios/setup#available-pods
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 7d6ce3a8..ba0f4456 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -134,24 +134,24 @@ PODS:
- GoogleUtilities/Environment (~> 7.2)
- nanopb (~> 2.30907.0)
- PromisesObjC (~> 1.2)
- - GoogleUtilities/AppDelegateSwizzler (7.4.0):
+ - GoogleUtilities/AppDelegateSwizzler (7.4.1):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- - GoogleUtilities/Environment (7.4.0):
+ - GoogleUtilities/Environment (7.4.1):
- PromisesObjC (~> 1.2)
- - GoogleUtilities/Logger (7.4.0):
+ - GoogleUtilities/Logger (7.4.1):
- GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (7.4.0):
+ - GoogleUtilities/MethodSwizzler (7.4.1):
- GoogleUtilities/Logger
- - GoogleUtilities/Network (7.4.0):
+ - GoogleUtilities/Network (7.4.1):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (7.4.0)"
- - GoogleUtilities/Reachability (7.4.0):
+ - "GoogleUtilities/NSData+zlib (7.4.1)"
+ - GoogleUtilities/Reachability (7.4.1):
- GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (7.4.0):
+ - GoogleUtilities/UserDefaults (7.4.1):
- GoogleUtilities/Logger
- libevent (2.1.12)
- nanopb (2.30907.0):
@@ -337,10 +337,15 @@ PODS:
- React-Core
- react-native-document-picker (5.1.0):
- React-Core
+ - react-native-image-picker (4.0.3):
+ - React-Core
- react-native-image-resizer (1.4.4):
- React-Core
- react-native-netinfo (6.0.0):
- React-Core
+ - react-native-photo-manipulator (1.2.4):
+ - React
+ - WCPhotoManipulator (~> 2.0.4)
- react-native-safe-area-context (3.2.0):
- React-Core
- react-native-splash-screen (3.2.0):
@@ -479,6 +484,7 @@ PODS:
- RNVectorIcons (7.1.0):
- React
- TOCropViewController (2.6.0)
+ - WCPhotoManipulator (2.0.4)
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
@@ -527,8 +533,10 @@ DEPENDENCIES:
- react-native-contacts (from `../node_modules/react-native-contacts`)
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
+ - react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-image-resizer (from `../node_modules/react-native-image-resizer`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
+ - react-native-photo-manipulator (from `../node_modules/react-native-photo-manipulator`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
@@ -586,6 +594,7 @@ SPEC REPOS:
- OpenSSL-Universal
- PromisesObjC
- TOCropViewController
+ - WCPhotoManipulator
- YogaKit
EXTERNAL SOURCES:
@@ -631,10 +640,14 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-date-picker"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
+ react-native-image-picker:
+ :path: "../node_modules/react-native-image-picker"
react-native-image-resizer:
:path: "../node_modules/react-native-image-resizer"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
+ react-native-photo-manipulator:
+ :path: "../node_modules/react-native-photo-manipulator"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-splash-screen:
@@ -721,7 +734,7 @@ SPEC CHECKSUMS:
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
GoogleAppMeasurement: c542a2feaac9ab98fd074e8f1a02c3585bbfbd47
GoogleDataTransport: 8b0e733ea77c9218778e5a9e34ba9508b8328939
- GoogleUtilities: 284cddc7fffc14ae1907efb6f78ab95c1fccaedc
+ GoogleUtilities: f8a43108b38a68eebe8b3540e1f4f2d28843ce20
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
nanopb: 59221d7f958fb711001e6a449489542d92ae113e
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
@@ -741,8 +754,10 @@ SPEC CHECKSUMS:
react-native-contacts: 931baebf460125c5a7bbce1c4521a96c69795123
react-native-date-picker: 2dfef0fcb6c36d078bc62f5de3ca79eff7f42486
react-native-document-picker: f2f73db94328c84e22144e369fb4a3ede47bc1f5
+ react-native-image-picker: 474cf2c33c2b6671da53d293a16c97995f0aec15
react-native-image-resizer: 13ac4af788f88af36d0353a1324401ebabd04fe4
react-native-netinfo: e849fc21ca2f4128a5726c801a82fc6f4a6db50d
+ react-native-photo-manipulator: e44c14a28bf7c9b7657a0e0ac79327c1a4d8fe2c
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa
@@ -773,9 +788,10 @@ SPEC CHECKSUMS:
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59
TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38
+ WCPhotoManipulator: 45b7be19b75c9edf6d2b44f2f61dbc3673862a8f
Yoga: 7d13633d129fd179e01b8953d38d47be90db185a
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
-PODFILE CHECKSUM: e24412577971b52c81c348785bf01cb915155d6d
+PODFILE CHECKSUM: 506904e1c9d422356d8a7be45ae9115719e4d7be
COCOAPODS: 1.10.1
diff --git a/package.json b/package.json
index ea8c946a..300eec0c 100644
--- a/package.json
+++ b/package.json
@@ -45,9 +45,12 @@
"react-native-haptic-feedback": "^1.11.0",
"react-native-hyperlink": "^0.0.19",
"react-native-image-crop-picker": "^0.36.0",
+ "react-native-image-pan-zoom": "^2.1.12",
+ "react-native-image-picker": "^4.0.3",
"react-native-image-resizer": "^1.4.4",
"react-native-inappbrowser-reborn": "^3.5.0",
"react-native-linear-gradient": "^2.5.6",
+ "react-native-photo-manipulator": "^1.2.4",
"react-native-picker-select": "^7.0.0",
"react-native-push-notifications": "^3.0.10",
"react-native-reanimated": "2.0.0-rc.0",
@@ -105,4 +108,4 @@
"./node_modules/react-native-gesture-handler/jestSetup.js"
]
}
-} \ No newline at end of file
+}
diff --git a/src/components/comments/CommentsCount.tsx b/src/components/comments/CommentsCount.tsx
new file mode 100644
index 00000000..90514193
--- /dev/null
+++ b/src/components/comments/CommentsCount.tsx
@@ -0,0 +1,48 @@
+import {useNavigation} from '@react-navigation/core';
+import React from 'react';
+import {StyleSheet, Text} from 'react-native';
+import {TouchableOpacity} from 'react-native-gesture-handler';
+import CommentsIcon from '../../assets/icons/moment-comment-icon.svg';
+import {MomentPostType, ScreenType} from '../../types';
+import {normalize} from '../../utils';
+
+interface CommentsCountProps {
+ moment: MomentPostType;
+ screenType: ScreenType;
+}
+
+const CommentsCount: React.FC<CommentsCountProps> = ({moment, screenType}) => {
+ const navigation = useNavigation();
+ return (
+ <TouchableOpacity
+ style={styles.countContainer}
+ onPress={() =>
+ navigation.navigate('MomentCommentsScreen', {
+ moment_id: moment.moment_id,
+ screenType,
+ })
+ }>
+ <CommentsIcon width={25} height={25} />
+ <Text style={styles.count}>{moment.comments_count}</Text>
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ countContainer: {
+ minWidth: 50,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ count: {
+ fontWeight: '500',
+ fontSize: normalize(11),
+ lineHeight: normalize(13),
+ letterSpacing: normalize(0.05),
+ textAlign: 'center',
+ color: 'white',
+ marginTop: normalize(5),
+ },
+});
+export default CommentsCount;
diff --git a/src/components/comments/ZoomInCropper.tsx b/src/components/comments/ZoomInCropper.tsx
new file mode 100644
index 00000000..94e772b6
--- /dev/null
+++ b/src/components/comments/ZoomInCropper.tsx
@@ -0,0 +1,199 @@
+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, image} = 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 (image.sourceURL) {
+ Image.getSize(
+ image.sourceURL,
+ (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 &&
+ image.sourceURL
+ ) {
+ PhotoManipulator.crop(image.sourceURL, {
+ x: x0,
+ y: y1,
+ width: Math.abs(x0 - x1),
+ height: Math.abs(y0 - y1),
+ })
+ .then((croppedURL) => {
+ navigation.navigate('CaptionScreen', {
+ screenType,
+ title: title,
+ image: {filename: croppedURL, path: croppedURL},
+ });
+ })
+ .catch((err) => console.log('err: ', err));
+ } else if (
+ x0 === undefined &&
+ x1 === undefined &&
+ y0 === undefined &&
+ y1 === undefined &&
+ image.sourceURL
+ ) {
+ navigation.navigate('CaptionScreen', {
+ screenType,
+ title: title,
+ image: {filename: image.sourceURL, path: image.sourceURL},
+ });
+ }
+ };
+
+ /* 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(
+ image.path,
+ (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: image.sourceURL,
+ }}
+ />
+ </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'},
+});
diff --git a/src/components/common/MomentTags.tsx b/src/components/common/MomentTags.tsx
index bdd1fbeb..4afacddb 100644
--- a/src/components/common/MomentTags.tsx
+++ b/src/components/common/MomentTags.tsx
@@ -66,19 +66,21 @@ const MomentTags: React.FC<MomentTagsProps> = ({
useEffect(() => {
setTimeout(
() => {
- imageRef.current.measure(
- (
- fx: number, // location of ref relative to parent element
- fy: number,
- width: number,
- height: number,
- _x: number, // location of ref relative to entire screen
- _y: number,
- ) => {
- setOffset([fx, fy]);
- setImageDimensions([width, height]);
- },
- );
+ if (imageRef && imageRef.current) {
+ imageRef.current.measure(
+ (
+ fx: number, // location of ref relative to parent element
+ fy: number,
+ width: number,
+ height: number,
+ _x: number, // location of ref relative to entire screen
+ _y: number,
+ ) => {
+ setOffset([fx, fy]);
+ setImageDimensions([width, height]);
+ },
+ );
+ }
},
editing ? 100 : 0,
);
diff --git a/src/components/moments/IndividualMomentTitleBar.tsx b/src/components/moments/IndividualMomentTitleBar.tsx
index 4ae9471f..c6bf1423 100644
--- a/src/components/moments/IndividualMomentTitleBar.tsx
+++ b/src/components/moments/IndividualMomentTitleBar.tsx
@@ -1,45 +1,32 @@
import React from 'react';
-import {
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- ViewProps,
-} from 'react-native';
-import CloseIcon from '../../assets/ionicons/close-outline.svg';
-import {normalize} from '../../utils';
+import {StyleSheet, Text, View, ViewProps} from 'react-native';
+import {normalize, SCREEN_WIDTH} from '../../utils';
interface IndividualMomentTitleBarProps extends ViewProps {
title: string;
- close: () => void;
}
const IndividualMomentTitleBar: React.FC<IndividualMomentTitleBarProps> = ({
title,
- close,
- style,
}) => {
return (
- <View style={[styles.container, style]}>
- <TouchableOpacity style={styles.closeButton} onPress={close}>
- <CloseIcon height={'100%'} width={'100%'} color={'white'} />
- </TouchableOpacity>
- <View style={styles.headerContainer}>
- <Text style={styles.header}>{title}</Text>
+ <View style={styles.mainContainer}>
+ <View style={styles.titleContainer}>
+ <Text
+ style={[
+ styles.title,
+ {
+ fontSize: title.length > 18 ? normalize(14) : normalize(16),
+ },
+ ]}>
+ {title}
+ </Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
- container: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'flex-start',
- },
- headerContainer: {
- width: '80%',
- },
- header: {
+ title: {
textAlign: 'center',
color: 'white',
fontSize: normalize(18),
@@ -47,10 +34,19 @@ const styles = StyleSheet.create({
lineHeight: normalize(21.48),
letterSpacing: normalize(1.3),
},
- closeButton: {
- height: '50%',
- aspectRatio: 1,
- left: '8%',
+ titleContainer: {
+ width: '80%',
+ position: 'absolute',
+ left: '10%',
+ right: '10%',
+ height: normalize(70),
+ },
+ mainContainer: {
+ flex: 1,
+ width: SCREEN_WIDTH * 0.6,
+ flexDirection: 'row',
+ justifyContent: 'flex-end',
+ marginVertical: '2%',
},
});
diff --git a/src/components/moments/Moment.tsx b/src/components/moments/Moment.tsx
index cde5b2e0..81e23076 100644
--- a/src/components/moments/Moment.tsx
+++ b/src/components/moments/Moment.tsx
@@ -7,8 +7,8 @@ import ImagePicker from 'react-native-image-crop-picker';
import LinearGradient from 'react-native-linear-gradient';
import DeleteIcon from '../../assets/icons/delete-logo.svg';
import DownIcon from '../../assets/icons/down_icon.svg';
-import PlusIcon from '../../assets/icons/plus-icon.svg';
import BigPlusIcon from '../../assets/icons/plus-icon-white.svg';
+import PlusIcon from '../../assets/icons/plus-icon.svg';
import UpIcon from '../../assets/icons/up_icon.svg';
import {TAGG_LIGHT_BLUE} from '../../constants';
import {ERROR_UPLOAD} from '../../constants/strings';
@@ -52,15 +52,11 @@ const Moment: React.FC<MomentProps> = ({
'Screenshots',
'UserLibrary',
],
- width: 580,
- height: 580,
- cropping: true,
- cropperToolbarTitle: 'Upload a moment',
- mediaType: 'photo',
+ mediaType: 'any',
})
.then((picture) => {
if ('path' in picture) {
- navigation.navigate('CaptionScreen', {
+ navigation.navigate('ZoomInCropper', {
screenType,
title: title,
image: picture,
diff --git a/src/components/moments/MomentPost.tsx b/src/components/moments/MomentPost.tsx
index d87028e3..6eccf5ab 100644
--- a/src/components/moments/MomentPost.tsx
+++ b/src/components/moments/MomentPost.tsx
@@ -1,38 +1,77 @@
-import React, {useEffect, useState} from 'react';
-import {StyleSheet} from 'react-native';
-import {useSelector} from 'react-redux';
-import {MomentPostContent, MomentPostHeader} from '.';
+import {useNavigation} from '@react-navigation/native';
+import React, {useContext, useEffect, useRef, useState} from 'react';
+import {
+ Image,
+ KeyboardAvoidingView,
+ Platform,
+ StatusBar,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ TouchableWithoutFeedback,
+ View,
+} from 'react-native';
+import Animated, {EasingNode} from 'react-native-reanimated';
+import {useDispatch, useSelector, useStore} from 'react-redux';
+import {headerBarOptions} from '../../routes';
+import {MomentContext} from '../../screens/profile/IndividualMoment';
import {deleteMomentTag, loadMomentTags} from '../../services';
+import {loadUserMoments} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
-import {MomentPostType, MomentTagType, ScreenType} from '../../types';
-import {normalize, SCREEN_HEIGHT} from '../../utils';
-
+import {MomentPostType, MomentTagType, ScreenType, UserType} from '../../types';
+import {
+ getTimePosted,
+ HeaderHeight,
+ isIPhoneX,
+ navigateToProfile,
+ normalize,
+ SCREEN_HEIGHT,
+ SCREEN_WIDTH,
+} from '../../utils';
+import {mentionPartTypes, renderTextWithMentions} from '../../utils/comments';
+import {AddComment} from '../comments';
+import CommentsCount from '../comments/CommentsCount';
+import {MomentTags} from '../common';
+import {MomentMoreInfoDrawer, TaggAvatar} from '../profile';
+import IndividualMomentTitleBar from './IndividualMomentTitleBar';
interface MomentPostProps {
moment: MomentPostType;
userXId: string | undefined;
screenType: ScreenType;
- index: number;
}
const MomentPost: React.FC<MomentPostProps> = ({
moment,
userXId,
screenType,
- index,
}) => {
+ const navigation = useNavigation();
+ const dispatch = useDispatch();
const {userId: loggedInUserId, username: loggedInUsername} = useSelector(
(state: RootState) => state.user.user,
);
-
- const {
- user: {username},
- } = useSelector((state: RootState) =>
+ const {user} = useSelector((state: RootState) =>
userXId ? state.userX[screenType][userXId] : state.user,
);
+ const state: RootState = useStore().getState();
+ const isOwnProfile = user.username === loggedInUsername;
+
const [tags, setTags] = useState<MomentTagType[]>([]);
+ const [visible, setVisible] = useState(false);
+ const [drawerVisible, setDrawerVisible] = useState(false);
+ const [hideText, setHideText] = useState(false);
+
+ const [fadeValue, setFadeValue] = useState<Animated.Value<number>>(
+ new Animated.Value(0),
+ );
+ const [commentCount, setCommentCount] = useState<number>(
+ moment.comments_count,
+ );
+ const [aspectRatio, setAspectRatio] = useState<number>(1);
const [momentTagId, setMomentTagId] = useState<string>('');
- const isOwnProfile = username === loggedInUsername;
+ const imageRef = useRef(null);
+ const {keyboardVisible} = useContext(MomentContext);
/*
* Load tags on initial render to pass tags data to moment header and content
@@ -41,7 +80,7 @@ const MomentPost: React.FC<MomentPostProps> = ({
loadMomentTags(moment.moment_id).then((response) => {
setTags(response ? response : []);
});
- }, []);
+ }, [moment]);
/*
* Check if loggedInUser has been tagged in the picture and set the id
@@ -71,34 +110,270 @@ const MomentPost: React.FC<MomentPostProps> = ({
}
};
+ useEffect(
+ () =>
+ navigation.setOptions({
+ ...headerBarOptions('white', ''),
+ headerTitle: () => (
+ <IndividualMomentTitleBar title={moment.moment_category} />
+ ),
+ }),
+ [moment.moment_id],
+ );
+
+ /*
+ * Determines if an image is 9:16 to set aspect ratio of current image and
+ * determine if image must be displayed in full screen or not
+ */
+ useEffect(() => {
+ Image.getSize(
+ moment.moment_url,
+ (w, h) => {
+ setAspectRatio(w / h);
+ },
+ (err) => console.log(err),
+ );
+ }, []);
+
+ /*
+ * To animate tags display
+ */
+ useEffect(() => {
+ const fade = async () => {
+ Animated.timing(fadeValue, {
+ toValue: 1,
+ duration: 250,
+ easing: EasingNode.linear,
+ }).start();
+ };
+ fade();
+ }, [fadeValue]);
+
+ useEffect(() => {
+ if (!keyboardVisible && hideText) {
+ setHideText(false);
+ }
+ }, [keyboardVisible, hideText]);
+
+ const MomentPosterPreview = () => (
+ <View style={styles.momentPosterContainer}>
+ <TouchableOpacity
+ onPress={() =>
+ navigateToProfile(state, dispatch, navigation, screenType, user)
+ }
+ style={styles.header}>
+ <TaggAvatar
+ style={styles.avatar}
+ userXId={userXId}
+ screenType={screenType}
+ editable={false}
+ />
+ <Text style={styles.headerText}>{user.username}</Text>
+ </TouchableOpacity>
+ </View>
+ );
+
return (
<>
- <MomentPostHeader
- style={styles.postHeader}
- userXId={userXId}
- screenType={screenType}
- username={isOwnProfile ? loggedInUsername : username}
- momentTagId={momentTagId}
- removeTag={removeTag}
- moment={moment}
- tags={tags}
- />
- <MomentPostContent
- style={styles.postContent}
- moment={moment}
- screenType={screenType}
- momentTags={tags}
- index={index}
- />
+ <StatusBar barStyle={'light-content'} />
+ <View style={styles.mainContainer}>
+ <View style={styles.imageContainer}>
+ <Image
+ source={{uri: moment.moment_url}}
+ style={[
+ styles.image,
+ {
+ height: SCREEN_WIDTH / aspectRatio,
+ },
+ ]}
+ resizeMode={'contain'}
+ ref={imageRef}
+ />
+ </View>
+ {visible && (
+ <Animated.View style={[styles.tagsContainer, {opacity: fadeValue}]}>
+ <MomentTags
+ editing={false}
+ tags={tags}
+ setTags={() => null}
+ imageRef={imageRef}
+ />
+ </Animated.View>
+ )}
+ <TouchableWithoutFeedback
+ onPress={() => {
+ setVisible(!visible);
+ setFadeValue(new Animated.Value(0));
+ }}>
+ <View style={styles.contentContainer}>
+ <View style={styles.topContainer}>
+ <MomentMoreInfoDrawer
+ isOpen={drawerVisible}
+ setIsOpen={setDrawerVisible}
+ isOwnProfile={isOwnProfile}
+ momentTagId={momentTagId}
+ removeTag={removeTag}
+ dismissScreenAndUpdate={() => {
+ dispatch(loadUserMoments(loggedInUserId));
+ navigation.goBack();
+ }}
+ screenType={screenType}
+ moment={moment}
+ tags={tags}
+ />
+ </View>
+ <KeyboardAvoidingView
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+ keyboardVerticalOffset={-20}>
+ <View style={styles.bottomContainer}>
+ {tags.length > 0 && (
+ <Image
+ source={require('../../assets/icons/tag_indicate.png')}
+ style={styles.tagIcon}
+ />
+ )}
+ <View style={styles.commentsCountContainer}>
+ <CommentsCount moment={moment} screenType={screenType} />
+ </View>
+ <MomentPosterPreview />
+ {!hideText && (
+ <>
+ {moment.caption !== '' &&
+ renderTextWithMentions({
+ value: moment.caption,
+ styles: styles.captionText,
+ partTypes: mentionPartTypes('white', 'caption'),
+ onPress: (userLocal: UserType) =>
+ navigateToProfile(
+ state,
+ dispatch,
+ navigation,
+ screenType,
+ userLocal,
+ ),
+ })}
+ </>
+ )}
+ <View>
+ <AddComment
+ placeholderText={'Add a comment here!'}
+ momentId={moment.moment_id}
+ callback={() => {
+ setCommentCount(commentCount + 1);
+ }}
+ onFocus={() => {
+ setHideText(true);
+ }}
+ isKeyboardAvoiding={false}
+ theme={'dark'}
+ />
+ <Text style={styles.text}>
+ {getTimePosted(moment.date_created)}
+ </Text>
+ </View>
+ </View>
+ </KeyboardAvoidingView>
+ </View>
+ </TouchableWithoutFeedback>
+ </View>
</>
);
};
const styles = StyleSheet.create({
- postHeader: {},
- postContent: {
- minHeight: SCREEN_HEIGHT * 0.8,
- paddingBottom: normalize(20),
+ image: {
+ zIndex: 0,
+ },
+ imageContainer: {
+ height: SCREEN_HEIGHT,
+ width: SCREEN_WIDTH,
+ flexDirection: 'column',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ },
+ text: {
+ marginHorizontal: '5%',
+ color: 'white',
+ fontWeight: '500',
+ textAlign: 'right',
+ marginTop: 5,
+ },
+ captionText: {
+ position: 'relative',
+ marginHorizontal: '5%',
+ color: '#ffffff',
+ fontWeight: '500',
+ fontSize: normalize(13),
+ lineHeight: normalize(15.51),
+ letterSpacing: normalize(0.6),
+ marginBottom: normalize(5),
+ width: SCREEN_WIDTH * 0.79,
+ },
+ tagIcon: {
+ width: normalize(30),
+ height: normalize(30),
+ bottom: normalize(20),
+ left: '5%',
+ },
+ avatar: {
+ width: 48,
+ aspectRatio: 1,
+ borderRadius: 100,
+ marginLeft: '3%',
+ },
+ headerText: {
+ fontSize: 15,
+ fontWeight: 'bold',
+ color: 'white',
+ paddingHorizontal: '3%',
+ },
+ header: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ marginBottom: normalize(15),
+ alignSelf: 'flex-start',
+ },
+ momentPosterContainer: {
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ commentsCountContainer: {
+ position: 'absolute',
+ right: '2%',
+ bottom: SCREEN_HEIGHT * 0.12,
+ },
+ bottomContainer: {
+ flexDirection: 'column',
+ justifyContent: 'flex-end',
+ },
+ topContainer: {
+ paddingTop: isIPhoneX() ? HeaderHeight : '6%',
+ alignSelf: 'flex-end',
+ paddingRight: '8%',
+ },
+ contentContainer: {
+ position: 'absolute',
+ width: SCREEN_WIDTH,
+ height: SCREEN_HEIGHT,
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ paddingBottom: '24%',
+ },
+ tagsContainer: {
+ position: 'absolute',
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0,
+ marginBottom: '3%',
+ },
+ mainContainer: {
+ backgroundColor: 'black',
+ width: SCREEN_WIDTH,
+ height: SCREEN_HEIGHT,
+ flexDirection: 'column',
+ justifyContent: 'center',
},
});
diff --git a/src/components/moments/MomentPostHeader.tsx b/src/components/moments/MomentPostHeader.tsx
deleted file mode 100644
index 5f26951a..00000000
--- a/src/components/moments/MomentPostHeader.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import {useNavigation} from '@react-navigation/native';
-import React, {useState} from 'react';
-import {
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
- ViewProps,
-} from 'react-native';
-import {useDispatch, useSelector, useStore} from 'react-redux';
-import {loadUserMoments} from '../../store/actions';
-import {RootState} from '../../store/rootReducer';
-import {MomentTagType, MomentType, ScreenType} from '../../types';
-import {fetchUserX, userXInStore} from '../../utils';
-import {MomentMoreInfoDrawer} from '../profile';
-import TaggAvatar from '../profile/TaggAvatar';
-
-interface MomentPostHeaderProps extends ViewProps {
- userXId?: string;
- screenType: ScreenType;
- username: string;
- momentTagId: string;
- removeTag: () => Promise<void>;
- moment: MomentType;
- tags: MomentTagType[];
-}
-
-const MomentPostHeader: React.FC<MomentPostHeaderProps> = ({
- userXId,
- screenType,
- username,
- style,
- momentTagId,
- removeTag,
- moment,
- tags,
-}) => {
- const [drawerVisible, setDrawerVisible] = useState(false);
- const dispatch = useDispatch();
- const navigation = useNavigation();
- const {userId: loggedInUserId, username: loggedInUserName} = useSelector(
- (state: RootState) => state.user.user,
- );
- const state: RootState = useStore().getState();
- const isOwnProfile = loggedInUserName === username;
- const navigateToProfile = async () => {
- if (userXId && !userXInStore(state, screenType, userXId)) {
- await fetchUserX(
- dispatch,
- {userId: userXId, username: username},
- screenType,
- );
- }
- navigation.navigate('Profile', {
- userXId: isOwnProfile ? undefined : userXId,
- screenType,
- });
- };
-
- return (
- <View style={[styles.container, style]}>
- <TouchableOpacity onPress={navigateToProfile} style={styles.header}>
- <TaggAvatar
- style={styles.avatar}
- userXId={userXId}
- screenType={screenType}
- editable={false}
- />
- <Text style={styles.headerText}>{username}</Text>
- </TouchableOpacity>
- <MomentMoreInfoDrawer
- isOpen={drawerVisible}
- setIsOpen={setDrawerVisible}
- isOwnProfile={isOwnProfile}
- momentTagId={momentTagId}
- removeTag={removeTag}
- dismissScreenAndUpdate={() => {
- dispatch(loadUserMoments(loggedInUserId));
- navigation.goBack();
- }}
- screenType={screenType}
- moment={moment}
- tags={tags}
- />
- </View>
- );
-};
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'space-around',
- flexDirection: 'row',
- alignItems: 'center',
- marginVertical: '2%',
- },
- header: {
- alignItems: 'center',
- flexDirection: 'row',
- flex: 1,
- },
- avatar: {
- flex: 0.2,
- aspectRatio: 1,
- borderRadius: 999999,
- marginLeft: '3%',
- },
- headerText: {
- fontSize: 15,
- fontWeight: 'bold',
- color: 'white',
- paddingHorizontal: '3%',
- flex: 1,
- },
-});
-export default MomentPostHeader;
diff --git a/src/components/moments/index.ts b/src/components/moments/index.ts
index c1419cfd..cac2da2e 100644
--- a/src/components/moments/index.ts
+++ b/src/components/moments/index.ts
@@ -1,7 +1,5 @@
export {default as IndividualMomentTitleBar} from './IndividualMomentTitleBar';
export {default as CaptionScreenHeader} from './CaptionScreenHeader';
-export {default as MomentPostHeader} from './MomentPostHeader';
-export {default as MomentPostContent} from './MomentPostContent';
export {default as Moment} from './Moment';
export {default as TagFriendsFooter} from './TagFriendsFoooter';
export {default as MomentPost} from './MomentPost';
diff --git a/src/components/moments/MomentPostContent.tsx b/src/components/moments/legacy/MomentPostContent.tsx
index aca2999c..6388be27 100644
--- a/src/components/moments/MomentPostContent.tsx
+++ b/src/components/moments/legacy/MomentPostContent.tsx
@@ -4,26 +4,29 @@ import {Image, StyleSheet, Text, View, ViewProps} from 'react-native';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import Animated, {EasingNode} from 'react-native-reanimated';
import {useDispatch, useStore} from 'react-redux';
-import {MomentContext} from '../../screens/profile/IndividualMoment';
-import {RootState} from '../../store/rootReducer';
+import {MomentContext} from '../../../screens/profile/IndividualMoment';
+import {RootState} from '../../../store/rootReducer';
import {
MomentCommentPreviewType,
MomentPostType,
MomentTagType,
ScreenType,
UserType,
-} from '../../types';
+} from '../../../types';
import {
getLoggedInUserAsProfilePreview,
getTimePosted,
navigateToProfile,
normalize,
SCREEN_WIDTH,
-} from '../../utils';
-import {mentionPartTypes, renderTextWithMentions} from '../../utils/comments';
-import {AddComment} from '../comments';
-import {MomentTags} from '../common';
-import MomentCommentPreview from './MomentCommentPreview';
+} from '../../../utils';
+import {
+ mentionPartTypes,
+ renderTextWithMentions,
+} from '../../../utils/comments';
+import {AddComment} from '../../comments';
+import {MomentTags} from '../../common';
+import MomentCommentPreview from '../MomentCommentPreview';
interface MomentPostContentProps extends ViewProps {
screenType: ScreenType;
diff --git a/src/components/profile/MomentMoreInfoDrawer.tsx b/src/components/profile/MomentMoreInfoDrawer.tsx
index a796ffd8..dc4ebe32 100644
--- a/src/components/profile/MomentMoreInfoDrawer.tsx
+++ b/src/components/profile/MomentMoreInfoDrawer.tsx
@@ -3,7 +3,6 @@ import React, {useEffect, useState} from 'react';
import {
Alert,
GestureResponderEvent,
- StyleSheet,
TextStyle,
TouchableOpacity,
ViewProps,
@@ -169,7 +168,6 @@ const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
return (
<>
<TouchableOpacity
- style={styles.icon}
onPress={() => {
setIsOpen(true);
}}>
@@ -184,10 +182,4 @@ const MomentMoreInfoDrawer: React.FC<MomentMoreInfoDrawerProps> = (props) => {
);
};
-const styles = StyleSheet.create({
- icon: {
- marginRight: '3%',
- },
-});
-
export default MomentMoreInfoDrawer;
diff --git a/src/components/profile/PublicProfile.tsx b/src/components/profile/PublicProfile.tsx
index 8a80c56f..6b991d7c 100644
--- a/src/components/profile/PublicProfile.tsx
+++ b/src/components/profile/PublicProfile.tsx
@@ -87,7 +87,9 @@ const PublicProfile: React.FC<ContentProps> = ({
scrollViewRef.current
) {
setScrollEnabled(false);
- scrollViewRef.current.scrollTo({y: 0});
+ if (scrollViewRef && scrollViewRef.current) {
+ scrollViewRef.current.scrollTo({y: 0});
+ }
navigation.navigate('MomentUploadPrompt', {
screenType,
momentCategory: momentCategories[0],
diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx
index 8fce5e2f..b58e03cc 100644
--- a/src/routes/main/MainStackNavigator.tsx
+++ b/src/routes/main/MainStackNavigator.tsx
@@ -38,7 +38,10 @@ export type MainStackParams = {
};
CaptionScreen: {
title?: string;
- image?: Image;
+ image?: {
+ filename: string;
+ path: string;
+ };
screenType: ScreenType;
selectedTags?: MomentTagType[];
moment?: MomentType;
@@ -107,6 +110,11 @@ export type MainStackParams = {
ChatList: undefined;
Chat: undefined;
NewChatModal: undefined;
+ ZoomInCropper: {
+ image: Image;
+ screenType: ScreenType;
+ title: string;
+ };
};
export const MainStack = createStackNavigator<MainStackParams>();
diff --git a/src/routes/main/MainStackScreen.tsx b/src/routes/main/MainStackScreen.tsx
index 3be2ff28..9e3747f9 100644
--- a/src/routes/main/MainStackScreen.tsx
+++ b/src/routes/main/MainStackScreen.tsx
@@ -39,6 +39,7 @@ import MutualBadgeHolders from '../../screens/suggestedPeople/MutualBadgeHolders
import {ScreenType} from '../../types';
import {AvatarHeaderHeight, ChatHeaderHeight, SCREEN_WIDTH} from '../../utils';
import {MainStack, MainStackParams} from './MainStackNavigator';
+import {ZoomInCropper} from '../../components/comments/ZoomInCropper';
/**
* Profile : To display the logged in user's profile when the userXId passed in to it is (undefined | null | empty string) else displays profile of the user being visited.
@@ -209,6 +210,7 @@ const MainStackScreen: React.FC<MainStackProps> = ({route}) => {
options={{
...modalStyle,
gestureEnabled: false,
+ ...headerBarOptions('white', ''),
}}
/>
<MainStack.Screen
@@ -325,6 +327,13 @@ const MainStackScreen: React.FC<MainStackProps> = ({route}) => {
gestureEnabled: false,
}}
/>
+ <MainStack.Screen
+ name="ZoomInCropper"
+ component={ZoomInCropper}
+ options={{
+ gestureEnabled: false,
+ }}
+ />
</MainStack.Navigator>
);
};
diff --git a/src/screens/main/NotificationsScreen.tsx b/src/screens/main/NotificationsScreen.tsx
index 03842b0a..84c15f66 100644
--- a/src/screens/main/NotificationsScreen.tsx
+++ b/src/screens/main/NotificationsScreen.tsx
@@ -36,8 +36,9 @@ const NotificationsScreen: React.FC = () => {
);
const [refreshing, setRefreshing] = useState(false);
// used for figuring out which ones are unread
- const [lastViewed, setLastViewed] =
- useState<moment.Moment | undefined>(undefined);
+ const [lastViewed, setLastViewed] = useState<moment.Moment | undefined>(
+ undefined,
+ );
const {notifications} = useSelector(
(state: RootState) => state.notifications,
);
diff --git a/src/screens/moments/TagFriendsScreen.tsx b/src/screens/moments/TagFriendsScreen.tsx
index 570c3776..15926b5a 100644
--- a/src/screens/moments/TagFriendsScreen.tsx
+++ b/src/screens/moments/TagFriendsScreen.tsx
@@ -34,6 +34,8 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
const navigation = useNavigation();
const imageRef = useRef(null);
const [tags, setTags] = useState<MomentTagType[]>([]);
+ const [imageWidth, setImageWidth] = useState<number>(0);
+ const [imageHeight, setImageHeight] = useState<number>(0);
/*
* Update list of tagged users from route params
@@ -52,6 +54,32 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
});
};
+ /*
+ * Calculating image width and height with respect to it's enclosing view's dimensions
+ */
+ useEffect(() => {
+ if (imageRef && imageRef.current) {
+ Image.getSize(
+ imagePath,
+ (w, h) => {
+ const imageAspectRatio = w / h;
+
+ // aspectRatio: >= 1 [Landscape] [1:1]
+ if (imageAspectRatio >= 1) {
+ setImageWidth(SCREEN_WIDTH);
+ setImageHeight(SCREEN_WIDTH / imageAspectRatio);
+ }
+ // aspectRatio: < 1 [Portrait]
+ else if (imageAspectRatio < 1) {
+ setImageHeight(SCREEN_WIDTH);
+ setImageWidth(SCREEN_WIDTH * imageAspectRatio);
+ }
+ },
+ (err) => console.log(err),
+ );
+ }
+ }, []);
+
return (
<SearchBackground>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
@@ -84,9 +112,16 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
}>
<Image
ref={imageRef}
- style={styles.image}
+ style={[
+ {
+ width: imageWidth,
+ height: imageHeight,
+ marginVertical: (SCREEN_WIDTH - imageHeight) / 2,
+ marginHorizontal: (SCREEN_WIDTH - imageWidth) / 2,
+ },
+ styles.image,
+ ]}
source={{uri: imagePath}}
- resizeMode={'cover'}
/>
</TouchableWithoutFeedback>
{tags.length !== 0 && (
@@ -131,12 +166,7 @@ const styles = StyleSheet.create({
header: {
marginVertical: 20,
},
- image: {
- position: 'relative',
- width: SCREEN_WIDTH,
- aspectRatio: 1,
- marginBottom: '3%',
- },
+ image: {zIndex: 0, justifyContent: 'center', alignSelf: 'center'},
text: {
position: 'relative',
backgroundColor: 'white',
diff --git a/src/screens/onboarding/BasicInfoOnboarding.tsx b/src/screens/onboarding/BasicInfoOnboarding.tsx
index d5998ac1..4c8da021 100644
--- a/src/screens/onboarding/BasicInfoOnboarding.tsx
+++ b/src/screens/onboarding/BasicInfoOnboarding.tsx
@@ -71,8 +71,9 @@ const BasicInfoOnboarding: React.FC<BasicInfoOnboardingProps> = ({route}) => {
const [invalidWithError, setInvalidWithError] = useState(
'Please enter a valid ',
);
- const [autoCapitalize, setAutoCap] =
- useState<'none' | 'sentences' | 'words' | 'characters' | undefined>('none');
+ const [autoCapitalize, setAutoCap] = useState<
+ 'none' | 'sentences' | 'words' | 'characters' | undefined
+ >('none');
const [fadeValue, setFadeValue] = useState<Animated.Value<number>>(
new Animated.Value(0),
);
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 253346d5..75533a9b 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -197,7 +197,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
<Image
style={styles.image}
source={{uri: moment ? moment.moment_url : image?.path}}
- resizeMode={'cover'}
+ resizeMode={'contain'}
/>
<MentionInputControlled
containerStyle={styles.text}
diff --git a/src/screens/profile/IndividualMoment.tsx b/src/screens/profile/IndividualMoment.tsx
index f8113aba..ca31ad5b 100644
--- a/src/screens/profile/IndividualMoment.tsx
+++ b/src/screens/profile/IndividualMoment.tsx
@@ -1,20 +1,14 @@
-import {BlurView} from '@react-native-community/blur';
import {RouteProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
import React, {useEffect, useRef, useState} from 'react';
-import {FlatList, Keyboard, StyleSheet} from 'react-native';
+import {FlatList, Keyboard} from 'react-native';
import {useSelector} from 'react-redux';
-import {IndividualMomentTitleBar, MomentPost} from '../../components';
+import {MomentPost, TabsGradient} from '../../components';
import {AVATAR_DIM} from '../../constants';
import {MainStackParams} from '../../routes';
import {RootState} from '../../store/rootreducer';
import {MomentPostType} from '../../types';
-import {
- isIPhoneX,
- normalize,
- SCREEN_HEIGHT,
- StatusBarHeight,
-} from '../../utils';
+import {isIPhoneX} from '../../utils';
/**
* Individual moment view opened when user clicks on a moment tile
@@ -39,10 +33,7 @@ interface IndividualMomentProps {
navigation: IndividualMomentNavigationProp;
}
-const IndividualMoment: React.FC<IndividualMomentProps> = ({
- route,
- navigation,
-}) => {
+const IndividualMoment: React.FC<IndividualMomentProps> = ({route}) => {
const {
userXId,
screenType,
@@ -84,55 +75,32 @@ const IndividualMoment: React.FC<IndividualMomentProps> = ({
keyboardVisible,
scrollTo,
}}>
- <BlurView
- blurType="light"
- blurAmount={30}
- reducedTransparencyFallbackColor="white"
- style={styles.contentContainer}>
- <IndividualMomentTitleBar
- style={styles.header}
- close={() => navigation.goBack()}
- title={moment_category}
- />
- <FlatList
- ref={scrollRef}
- data={momentData}
- contentContainerStyle={styles.listContentContainer}
- renderItem={({item, index}) => (
- <MomentPost
- moment={item}
- userXId={userXId}
- screenType={screenType}
- index={index}
- />
- )}
- keyExtractor={(item, _) => item.moment_id}
- showsVerticalScrollIndicator={false}
- initialScrollIndex={initialIndex}
- onScrollToIndexFailed={() => {
- // TODO: code below does not work, index resets to 0
- // const wait = new Promise((resolve) => setTimeout(resolve, 500));
- // wait.then(() => {
- // console.log('scrolling to ', initialIndex);
- // scrollRef.current?.scrollToIndex({index: initialIndex});
- // });
- }}
- />
- </BlurView>
+ <FlatList
+ ref={scrollRef}
+ data={momentData}
+ renderItem={({item}) => (
+ <MomentPost
+ key={item.moment_id}
+ moment={item}
+ userXId={userXId}
+ screenType={screenType}
+ />
+ )}
+ keyExtractor={(item, _) => item.moment_id}
+ showsVerticalScrollIndicator={false}
+ initialScrollIndex={initialIndex}
+ onScrollToIndexFailed={(info) => {
+ setTimeout(() => {
+ scrollRef.current?.scrollToIndex({
+ index: info.index,
+ });
+ }, 500);
+ }}
+ pagingEnabled
+ />
+ <TabsGradient />
</MomentContext.Provider>
);
};
-const styles = StyleSheet.create({
- contentContainer: {
- paddingTop: StatusBarHeight,
- flex: 1,
- },
- header: {
- height: normalize(70),
- },
- listContentContainer: {
- paddingBottom: SCREEN_HEIGHT * 0.2,
- },
-});
export default IndividualMoment;
diff --git a/yarn.lock b/yarn.lock
index 9c1ebdf8..4e31b01a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2303,6 +2303,11 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
+color-convert@~0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
+ integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
+
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
@@ -6018,6 +6023,13 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-color@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-color/-/parse-color-1.0.0.tgz#7b748b95a83f03f16a94f535e52d7f3d94658619"
+ integrity sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=
+ dependencies:
+ color-convert "~0.5.0"
+
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -6445,6 +6457,16 @@ react-native-image-crop-picker@^0.36.0:
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.36.2.tgz#fcb35c1a12d805bedbb6d94a87078e86a6c9b49f"
integrity sha512-cTauoEHHzx14ZHA7Pt65e7RVnbn1WRYQz2ufTZp9/05EtNDrdsXwNhgtXdWVFbOhYB8qgUFQjy2NelkBOHIH3g==
+react-native-image-pan-zoom@^2.1.12:
+ version "2.1.12"
+ resolved "https://registry.yarnpkg.com/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz#eb98bf56fb5610379bdbfdb63219cc1baca98fd2"
+ integrity sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==
+
+react-native-image-picker@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/react-native-image-picker/-/react-native-image-picker-4.0.3.tgz#dd8d393e0c57321688885c74b52244ad36e532d6"
+ integrity sha512-S4a1jE4fAPDzmah/7OVTEAXGz1/wlGyClU+spygmek5rVLERR5BgwnkX3tLP/UvMQbfdPZNUbnH0hEe7su2AZg==
+
react-native-image-resizer@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/react-native-image-resizer/-/react-native-image-resizer-1.4.4.tgz#75eee65580de509ada674669d13e4d236caea2d5"
@@ -6485,6 +6507,13 @@ react-native-markdown-package@1.8.1:
react-native-lightbox "^0.7.0"
simple-markdown "^0.7.1"
+react-native-photo-manipulator@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/react-native-photo-manipulator/-/react-native-photo-manipulator-1.2.4.tgz#60da9c68c815695c43fa3ed8c77bd9f08d076158"
+ integrity sha512-EGkDxmVfom52G2jDWvY+rzzHVTlXLCfBs+IQut+VaH7TtShxQekzzqxFRr0Pch/0I5s6Vt+gjrhFZBIv7FweVg==
+ dependencies:
+ parse-color "^1.0.0"
+
react-native-picker-select@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/react-native-picker-select/-/react-native-picker-select-7.0.0.tgz#4808a1177f997e234bb8505849dfffe1a01fedac"