aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/common/GradientProgressBar.tsx25
-rw-r--r--src/components/moments/MomentPost.tsx81
-rw-r--r--src/components/moments/MomentUploadProgressBar.tsx17
-rw-r--r--src/components/profile/Content.tsx2
-rw-r--r--src/screens/profile/CaptionScreen.tsx72
-rw-r--r--src/store/actions/user.ts84
6 files changed, 170 insertions, 111 deletions
diff --git a/src/components/common/GradientProgressBar.tsx b/src/components/common/GradientProgressBar.tsx
index fc62bd3c..066295d0 100644
--- a/src/components/common/GradientProgressBar.tsx
+++ b/src/components/common/GradientProgressBar.tsx
@@ -2,20 +2,21 @@ import React, {FC} from 'react';
import {StyleSheet, ViewProps, ViewStyle} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import Animated, {useAnimatedStyle} from 'react-native-reanimated';
-import {
- TAGG_LIGHT_BLUE_2,
- TAGG_LIGHT_BLUE_3,
- TAGG_PURPLE,
-} from '../../constants';
import {normalize} from '../../utils';
interface GradientProgressBarProps extends ViewProps {
progress: Animated.SharedValue<number>;
+ toColor: string;
+ fromColor: string;
+ unfilledColor: string;
}
const GradientProgressBar: FC<GradientProgressBarProps> = ({
style,
progress,
+ toColor,
+ fromColor,
+ unfilledColor,
}) => {
const animatedProgressStyle = useAnimatedStyle<ViewStyle>(() => ({
width: `${(1 - progress.value) * 100}%`,
@@ -24,8 +25,16 @@ const GradientProgressBar: FC<GradientProgressBarProps> = ({
<LinearGradient
style={[styles.bar, style]}
useAngle={true}
- colors={[TAGG_PURPLE, TAGG_LIGHT_BLUE_2]}>
- <Animated.View style={[styles.blank, animatedProgressStyle]} />
+ colors={[fromColor, toColor]}>
+ <Animated.View
+ style={[
+ styles.blank,
+ animatedProgressStyle,
+ {
+ backgroundColor: unfilledColor,
+ },
+ ]}
+ />
</LinearGradient>
);
};
@@ -36,12 +45,12 @@ const styles = StyleSheet.create({
bar: {
height: normalize(10),
borderRadius: 6.5,
+ opacity: 1,
},
blank: {
alignSelf: 'flex-end',
height: normalize(10),
width: '80%',
- backgroundColor: TAGG_LIGHT_BLUE_3,
},
});
diff --git a/src/components/moments/MomentPost.tsx b/src/components/moments/MomentPost.tsx
index c232986d..921f7693 100644
--- a/src/components/moments/MomentPost.tsx
+++ b/src/components/moments/MomentPost.tsx
@@ -14,14 +14,18 @@ import {
} from 'react-native';
// @ts-ignore
import Pinchable from 'react-native-pinchable';
-import Animated, {EasingNode} from 'react-native-reanimated';
+import Animated, {
+ Easing,
+ EasingNode,
+ useSharedValue,
+ withTiming,
+} from 'react-native-reanimated';
import {SafeAreaView} from 'react-native-safe-area-context';
-import SimpleGradientProgressbarView from 'react-native-simple-gradient-progressbar-view';
import Video from 'react-native-video';
import {useDispatch, useSelector, useStore} from 'react-redux';
import {TaggedUsersDrawer} from '.';
import PauseIcon from '../../assets/icons/pause-icon.svg';
-import {TAGG_LIGHT_BLUE_2, TAGG_PURPLE} from '../../constants/constants';
+import {TAGG_PURPLE} from '../../constants/constants';
import {headerBarOptions} from '../../routes';
import {MomentContext} from '../../screens/profile/IndividualMoment';
import {deleteMomentTag, loadMomentTags} from '../../services';
@@ -30,16 +34,14 @@ import {RootState} from '../../store/rootReducer';
import {MomentPostType, MomentTagType, ScreenType, UserType} from '../../types';
import {
getTimePosted,
- 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 {GradientProgressBar, MomentTags} from '../common';
import {MomentMoreInfoDrawer, TaggAvatar} from '../profile';
import IndividualMomentTitleBar from './IndividualMomentTitleBar';
interface MomentPostProps {
@@ -75,9 +77,6 @@ const MomentPost: React.FC<MomentPostProps> = ({
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>('');
@@ -94,7 +93,7 @@ const MomentPost: React.FC<MomentPostProps> = ({
);
const mediaHeight = SCREEN_WIDTH / aspectRatio;
const [isVideoPaused, setIsVideoPaused] = useState<boolean>(false);
- const [videoProgress, setVideoProgress] = useState<number>(0);
+ const videoProgress = useSharedValue(0);
/*
* Load tags on initial render to pass tags data to moment header and content
*/
@@ -233,10 +232,16 @@ const MomentPost: React.FC<MomentPostProps> = ({
onProgress={({currentTime, seekableDuration}) => {
const localProgress = currentTime / seekableDuration;
if (!isNaN(localProgress)) {
- setVideoProgress(localProgress);
+ videoProgress.value = withTiming(localProgress, {
+ duration: 250,
+ easing: Easing.linear,
+ });
}
}}
- onEnd={updateMomentViewCount}
+ onEnd={() => {
+ updateMomentViewCount();
+ videoProgress.value = 0;
+ }}
/>
{isVideoPaused && (
<Animated.View
@@ -260,20 +265,6 @@ const MomentPost: React.FC<MomentPostProps> = ({
/>
);
- const ProgressBar = () => (
- <View style={styles.progressBaContainer}>
- <SimpleGradientProgressbarView
- progress={videoProgress}
- style={styles.progressBar}
- fromColor={TAGG_PURPLE}
- toColor={TAGG_LIGHT_BLUE_2}
- />
- <View
- style={[styles.progressDot, {left: videoProgress * SCREEN_WIDTH - 5}]}
- />
- </View>
- );
-
return (
<>
<StatusBar barStyle={'light-content'} />
@@ -353,7 +344,7 @@ const MomentPost: React.FC<MomentPostProps> = ({
<View style={styles.commentsCountContainer}>
<CommentsCount
momentId={moment.moment_id}
- count={commentCount}
+ count={moment.comments_count}
screenType={screenType}
/>
</View>
@@ -374,22 +365,18 @@ const MomentPost: React.FC<MomentPostProps> = ({
),
})}
<View>
- <AddComment
- placeholderText={'Add a comment here!'}
- momentId={moment.moment_id}
- callback={() => {
- setCommentCount(commentCount + 1);
- }}
- onFocus={() => {
- setHideText(true);
- }}
- isKeyboardAvoiding={false}
- theme={'dark'}
- />
- {isVideo && <ProgressBar />}
<Text style={styles.text}>
{getTimePosted(moment.date_created)}
</Text>
+ {isVideo && (
+ <GradientProgressBar
+ style={styles.progressBar}
+ progress={videoProgress}
+ toColor={'#fff'}
+ fromColor={'#fff'}
+ unfilledColor={'#808080'}
+ />
+ )}
</View>
</KeyboardAvoidingView>
</View>
@@ -409,7 +396,8 @@ const styles = StyleSheet.create({
color: 'white',
fontWeight: '500',
textAlign: 'right',
- marginTop: 18,
+ marginTop: 10,
+ marginBottom: 10,
},
captionText: {
position: 'relative',
@@ -501,10 +489,9 @@ const styles = StyleSheet.create({
top: '40%',
},
progressBar: {
- position: 'absolute',
- top: 0,
- width: SCREEN_WIDTH,
- height: 5,
+ width: SCREEN_WIDTH * 0.99,
+ height: 3,
+ marginHorizontal: 2,
},
progressDot: {
backgroundColor: '#fff',
@@ -516,10 +503,6 @@ const styles = StyleSheet.create({
position: 'absolute',
top: -2.5,
},
- progressBaContainer: {
- position: 'absolute',
- top: isIPhoneX() ? 75 : 70,
- },
profilePreviewContainer: {paddingHorizontal: '3%'},
});
diff --git a/src/components/moments/MomentUploadProgressBar.tsx b/src/components/moments/MomentUploadProgressBar.tsx
index d56a8337..96f9fa27 100644
--- a/src/components/moments/MomentUploadProgressBar.tsx
+++ b/src/components/moments/MomentUploadProgressBar.tsx
@@ -8,6 +8,11 @@ import {
withTiming,
} from 'react-native-reanimated';
import {useDispatch, useSelector} from 'react-redux';
+import {
+ TAGG_LIGHT_BLUE_2,
+ TAGG_LIGHT_BLUE_3,
+ TAGG_PURPLE,
+} from '../../constants';
import {checkMomentDoneProcessing} from '../../services';
import {loadUserMoments} from '../../store/actions';
import {setMomentUploadProgressBar} from '../../store/reducers';
@@ -51,7 +56,6 @@ const MomentUploadProgressBar: React.FC<MomentUploadProgressBarProps> =
});
// change status to Done 1s after the progress bar animation is done
setTimeout(() => {
- dispatch(loadUserMoments(loggedInUserId));
dispatch({
type: setMomentUploadProgressBar.type,
payload: {
@@ -110,6 +114,9 @@ const MomentUploadProgressBar: React.FC<MomentUploadProgressBarProps> =
}, [momentUploadProgressBar?.status]);
useEffect(() => {
+ if (momentUploadProgressBar?.status === MomentUploadStatusType.Done) {
+ dispatch(loadUserMoments(loggedInUserId));
+ }
if (
momentUploadProgressBar?.status === MomentUploadStatusType.Done ||
momentUploadProgressBar?.status === MomentUploadStatusType.Error
@@ -143,7 +150,13 @@ const MomentUploadProgressBar: React.FC<MomentUploadProgressBarProps> =
{showLoading && (
<>
<Text style={styles.text}>Uploading Moment...</Text>
- <GradientProgressBar style={styles.bar} progress={progress} />
+ <GradientProgressBar
+ style={styles.bar}
+ progress={progress}
+ toColor={TAGG_LIGHT_BLUE_2}
+ fromColor={TAGG_PURPLE}
+ unfilledColor={TAGG_LIGHT_BLUE_3}
+ />
</>
)}
{momentUploadProgressBar.status === MomentUploadStatusType.Done && (
diff --git a/src/components/profile/Content.tsx b/src/components/profile/Content.tsx
index 9edd890d..df692a3f 100644
--- a/src/components/profile/Content.tsx
+++ b/src/components/profile/Content.tsx
@@ -136,7 +136,7 @@ const Content: React.FC<ContentProps> = ({userXId, screenType}) => {
onScroll={scrollHandler}
showsVerticalScrollIndicator={false}
scrollEventThrottle={1}
- stickyHeaderIndices={[4]}
+ stickyHeaderIndices={[5]}
scrollEnabled={scrollEnabled}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 3ee0bd5b..66106a6f 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -30,15 +30,14 @@ import {
ERROR_NO_MOMENT_CATEGORY,
ERROR_SOMETHING_WENT_WRONG_REFRESH,
ERROR_UPLOAD,
- SUCCESS_PIC_UPLOAD,
} from '../../constants/strings';
import * as RootNavigation from '../../RootNavigation';
import {MainStackParams} from '../../routes';
-import {patchMoment, postMoment, postMomentTags} from '../../services';
+import {patchMoment} from '../../services';
import {
+ handleImageMomentUpload,
handleVideoMomentUpload,
loadUserMoments,
- updateProfileCompletionStage,
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {MomentTagType} from '../../types';
@@ -138,11 +137,6 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
// then switch to the profile tab
navigation.popToTop();
RootNavigation.navigate('ProfileTab');
- setTimeout(() => {
- if (!isMediaAVideo) {
- Alert.alert(SUCCESS_PIC_UPLOAD);
- }
- }, 500);
} else {
// if editing, simply go back to profile screen
navigation.navigate('Profile', {
@@ -167,53 +161,29 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
handleFailed(true);
return;
}
- let profileCompletionStage;
- // separate upload logic for image/video
if (isMediaAVideo) {
- if (videoDuration) {
- dispatch(
- handleVideoMomentUpload(
- mediaUri,
- videoDuration,
- momentCategory,
- formattedTags(),
- ),
- );
- } else {
- handleFailed();
- return;
- }
- } else {
- const momentResponse = await postMoment(
- mediaUri,
- caption,
- momentCategory,
- userId,
+ dispatch(
+ handleVideoMomentUpload(
+ mediaUri,
+ videoDuration ?? 30,
+ momentCategory,
+ formattedTags(),
+ ),
);
- if (!momentResponse) {
- handleFailed();
- return;
- }
- profileCompletionStage = momentResponse.profile_completion_stage;
- const momentId = momentResponse.moment_id;
- if (momentId) {
- const momentTagResponse = await postMomentTags(
- momentId,
+ } else {
+ dispatch(
+ handleImageMomentUpload(
+ mediaUri,
+ caption,
+ momentCategory,
+ userId,
formattedTags(),
- );
- if (!momentTagResponse) {
- handleFailed();
- return;
- }
- }
- }
- if (!isMediaAVideo) {
- dispatch(loadUserMoments(userId));
- }
- if (profileCompletionStage) {
- dispatch(updateProfileCompletionStage(profileCompletionStage));
+ ),
+ );
}
- handleSuccess();
+ setTimeout(() => {
+ handleSuccess();
+ }, 500);
};
const handleSubmitEditChanges = async () => {
diff --git a/src/store/actions/user.ts b/src/store/actions/user.ts
index 1acbb519..14865f25 100644
--- a/src/store/actions/user.ts
+++ b/src/store/actions/user.ts
@@ -6,6 +6,7 @@ import {
handlePresignedURL,
handleVideoUpload,
loadProfileInfo,
+ postMoment,
postMomentTags,
removeBadgesService,
sendSuggestedPeopleLinked,
@@ -285,6 +286,89 @@ export const suggestedPeopleAnimatedTutorialFinished =
}
};
+export const handleImageMomentUpload =
+ (
+ imageUri: string,
+ caption: string,
+ momentCategory: string,
+ userId: string,
+ formattedTags: {
+ x: number;
+ y: number;
+ z: number;
+ user_id: string;
+ }[],
+ ): ThunkAction<Promise<void>, RootState, unknown, Action<string>> =>
+ async (dispatch) => {
+ try {
+ const handleError = (reason: string) => {
+ console.error('Moment video upload failed,', reason);
+ dispatch({
+ type: setMomentUploadProgressBar.type,
+ payload: {
+ momentUploadProgressBar: {
+ ...momentUploadProgressBar,
+ status: MomentUploadStatusType.Error,
+ },
+ },
+ });
+ };
+ let momentUploadProgressBar: MomentUploadProgressBarType = {
+ status: MomentUploadStatusType.UploadingToS3,
+ momentId: '',
+ originalVideoDuration: 1, // assume upload time for an image is same as a 1s video
+ };
+ // set progress bar as loading
+ dispatch({
+ type: setMomentUploadProgressBar.type,
+ payload: {momentUploadProgressBar},
+ });
+ // upload image moment
+ const momentPostResponse = await postMoment(
+ imageUri,
+ caption,
+ momentCategory,
+ userId,
+ );
+ if (!momentPostResponse) {
+ handleError('Moment post failed');
+ return;
+ }
+ const profileCompletionStage =
+ momentPostResponse.profile_completion_stage;
+ const momentId = momentPostResponse.moment_id;
+ if (!momentId) {
+ handleError('Unable to parse moment id from moment post response');
+ return;
+ }
+ // upload moment tags
+ const momentTagResponse = await postMomentTags(momentId, formattedTags);
+ if (!momentTagResponse) {
+ handleError('Moment tag post failed');
+ return;
+ }
+ if (profileCompletionStage) {
+ dispatch(updateProfileCompletionStage(profileCompletionStage));
+ } else {
+ console.error(
+ 'failed to parse profile complete stage from moment post response',
+ );
+ }
+ // mark progress bar state as done
+ dispatch({
+ type: setMomentUploadProgressBar.type,
+ payload: {
+ momentUploadProgressBar: {
+ ...momentUploadProgressBar,
+ status: MomentUploadStatusType.Done,
+ },
+ },
+ });
+ } catch (error) {
+ console.log(error);
+ }
+ };
+
/**
* state is now UploadingToS3:
* - get presigned url (backend creates the moment object)