From 545caa8c32e383551b1f1d5de61a300bc39100ff Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 23 Jun 2021 15:21:14 -0400
Subject: Cleanup code, Update route params for Caption Screen

---
 src/screens/profile/CaptionScreen.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 9e1b4674..bb02494d 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -51,7 +51,7 @@ interface CaptionScreenProps {
 }
 
 const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
-  const {title, image, screenType, selectedTags, moment} = route.params;
+  const {title, media, screenType, selectedTags, moment} = route.params;
   const {
     user: {userId},
   } = useSelector((state: RootState) => state.user);
@@ -120,12 +120,12 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
 
   const handleShare = async () => {
     setLoading(true);
-    if (!image?.filename || !title) {
+    if (!media || !title) {
       return;
     }
     const momentResponse = await postMoment(
-      image.filename,
-      image.path,
+      media.filename,
+      media.uri,
       caption,
       title,
       userId,
-- 
cgit v1.2.3-70-g09d2


From 205475150e32a309f25f878b4c58a4eba890cb01 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 23 Jun 2021 15:36:07 -0400
Subject: Cleanup code, Add support for video

---
 src/screens/profile/CaptionScreen.tsx | 43 +++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 14 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index bb02494d..48724620 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -51,7 +51,7 @@ interface CaptionScreenProps {
 }
 
 const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
-  const {title, media, screenType, selectedTags, moment} = route.params;
+  const {title, screenType, selectedTags, moment} = route.params;
   const {
     user: {userId},
   } = useSelector((state: RootState) => state.user);
@@ -62,6 +62,17 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
     selectedTags ? selectedTags : [],
   );
   const [taggedList, setTaggedList] = useState<string>('');
+  const mediaFilename = moment ? undefined : route.params.media!.filename;
+  const mediaUri = moment ? moment.moment_url : route.params.media!.uri;
+  // TODO: change this once moment refactor is done
+  const isMediaAVideo = moment
+    ? !(
+        moment.moment_url.endsWith('.jpg') ||
+        moment.moment_url.endsWith('.JPG') ||
+        moment.moment_url.endsWith('.png') ||
+        moment.moment_url.endsWith('.PNG')
+      )
+    : route.params.media?.type === 'video';
 
   useEffect(() => {
     setTags(selectedTags ? selectedTags : []);
@@ -120,12 +131,12 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
 
   const handleShare = async () => {
     setLoading(true);
-    if (!media || !title) {
+    if (moment || !mediaFilename || !title) {
       return;
     }
     const momentResponse = await postMoment(
-      media.filename,
-      media.uri,
+      mediaFilename,
+      mediaUri,
       caption,
       title,
       userId,
@@ -191,14 +202,18 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
             </View>
             <CaptionScreenHeader
               style={styles.header}
-              {...{title: moment ? moment.moment_category : title}}
-            />
-            {/* this is the image we want to center our tags' initial location within */}
-            <Image
-              style={styles.image}
-              source={{uri: moment ? moment.moment_url : image?.path}}
-              resizeMode={'cover'}
+              {...{title: moment ? moment.moment_category : title ?? ''}}
             />
+            {isMediaAVideo ? (
+              // <Video uri={mediaUri} style={styles.media} />
+              <></>
+            ) : (
+              <Image
+                style={styles.media}
+                source={{uri: mediaUri}}
+                resizeMode={'cover'}
+              />
+            )}
             <MentionInput
               containerStyle={styles.text}
               placeholder="Write something....."
@@ -212,8 +227,8 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
                 navigation.navigate('TagFriendsScreen', {
                   imagePath: moment
                     ? moment.moment_url
-                    : image
-                    ? image.path
+                    : media
+                    ? media.uri
                     : '',
                   selectedTags: tags,
                 })
@@ -257,7 +272,7 @@ const styles = StyleSheet.create({
   header: {
     marginVertical: 20,
   },
-  image: {
+  media: {
     position: 'relative',
     width: SCREEN_WIDTH,
     aspectRatio: 1,
-- 
cgit v1.2.3-70-g09d2


From f3651f53af4bf2a7163c82bb8c21bc6ec3940b4e Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 23 Jun 2021 15:37:21 -0400
Subject: Add react-native-video

---
 src/screens/chat/ChatListScreen.tsx   | 288 ++++++++++++++--------------------
 src/screens/profile/CaptionScreen.tsx |   4 +-
 2 files changed, 124 insertions(+), 168 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/screens/chat/ChatListScreen.tsx b/src/screens/chat/ChatListScreen.tsx
index 08b41151..0f5d8073 100644
--- a/src/screens/chat/ChatListScreen.tsx
+++ b/src/screens/chat/ChatListScreen.tsx
@@ -1,10 +1,26 @@
+import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
 import {StackNavigationProp} from '@react-navigation/stack';
-import React from 'react';
-import {StyleSheet} from 'react-native';
-import {SafeAreaView} from 'react-native-safe-area-context';
-import Video from 'react-native-video';
+import React, {useContext, useEffect, useMemo, useState} from 'react';
+import {Alert, SafeAreaView, StatusBar, StyleSheet, View} from 'react-native';
+import {useStore} from 'react-redux';
+import {ChannelList, Chat} from 'stream-chat-react-native';
+import {ChatContext} from '../../App';
+import {TabsGradient} from '../../components';
+import EmptyContentView from '../../components/common/EmptyContentView';
+import {ChannelPreview, MessagesHeader} from '../../components/messages';
 import {MainStackParams} from '../../routes';
-import {SCREEN_WIDTH} from '../../utils';
+import {RootState} from '../../store/rootReducer';
+import {
+  LocalAttachmentType,
+  LocalChannelType,
+  LocalCommandType,
+  LocalEventType,
+  LocalMessageType,
+  LocalReactionType,
+  LocalUserType,
+} from '../../types';
+import {connectChatAccount, HeaderHeight} from '../../utils';
+import NewChatModal from './NewChatModal';
 
 type ChatListScreenNavigationProp = StackNavigationProp<
   MainStackParams,
@@ -13,174 +29,114 @@ type ChatListScreenNavigationProp = StackNavigationProp<
 interface ChatListScreenProps {
   navigation: ChatListScreenNavigationProp;
 }
-
+/*
+ * Screen that displays all of the user's active conversations.
+ */
 const ChatListScreen: React.FC<ChatListScreenProps> = () => {
+  const {chatClient} = useContext(ChatContext);
+  const [modalVisible, setChatModalVisible] = useState(false);
+  const state: RootState = useStore().getState();
+  const loggedInUserId = state.user.user.userId;
+  const tabbarHeight = useBottomTabBarHeight();
+
+  const memoizedFilters = useMemo(
+    () => ({
+      members: {$in: [loggedInUserId]},
+      type: 'messaging',
+    }),
+    [],
+  );
+
+  const chatTheme = {
+    channelListMessenger: {
+      flatListContent: {
+        backgroundColor: 'white',
+        paddingBottom: tabbarHeight + HeaderHeight + 20,
+      },
+    },
+  };
+
+  useEffect(() => {
+    if (loggedInUserId) {
+      connectChatAccount(loggedInUserId, chatClient)
+        .then((success) => {
+          if (!success) {
+            Alert.alert('Something wrong with chat');
+          }
+        })
+        .catch((err) => {
+          console.log('Error connecting to chat: ', err);
+          Alert.alert('Something wrong with chat');
+        });
+    }
+  }, [loggedInUserId]);
+
   return (
-    <SafeAreaView>
-      <Video
-        // HLS m3u8 version
-        source={{
-          uri: 'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8',
-        }}
-        // mp4 version
-        // source={{
-        //   uri: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
-        // }}
-        volume={5}
-        style={styles.video}
-      />
-    </SafeAreaView>
+    <View style={styles.background}>
+      <SafeAreaView>
+        <StatusBar barStyle="dark-content" />
+        <MessagesHeader
+          createChannel={() => {
+            setChatModalVisible(true);
+          }}
+        />
+        <Chat client={chatClient} style={chatTheme}>
+          <View style={styles.chatContainer}>
+            <ChannelList<
+              LocalAttachmentType,
+              LocalChannelType,
+              LocalCommandType,
+              LocalEventType,
+              LocalMessageType,
+              LocalReactionType,
+              LocalUserType
+            >
+              filters={memoizedFilters}
+              options={{
+                presence: true,
+                state: true,
+                watch: true,
+              }}
+              sort={{last_message_at: -1}}
+              maxUnreadCount={99}
+              Preview={ChannelPreview}
+              EmptyStateIndicator={() => {
+                return <EmptyContentView viewType={'ChatList'} />;
+              }}
+            />
+          </View>
+        </Chat>
+        <NewChatModal {...{modalVisible, setChatModalVisible}} />
+      </SafeAreaView>
+      <TabsGradient />
+    </View>
   );
 };
 
 const styles = StyleSheet.create({
-  video: {
-    width: SCREEN_WIDTH,
-    aspectRatio: 2,
+  background: {
+    flex: 1,
+    backgroundColor: 'white',
+  },
+  container: {
+    flex: 1,
+    justifyContent: 'center',
+    alignItems: 'center',
+  },
+  placeholder: {
+    fontSize: 14,
+    fontWeight: 'bold',
+    marginBottom: 10,
+  },
+  button: {
+    backgroundColor: '#CCE4FC',
+    padding: 15,
+    borderRadius: 5,
+  },
+  chatContainer: {
+    height: '100%',
+    marginTop: 10,
   },
 });
 
 export default ChatListScreen;
-
-// import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
-// import {StackNavigationProp} from '@react-navigation/stack';
-// import React, {useContext, useEffect, useMemo, useState} from 'react';
-// import {Alert, SafeAreaView, StatusBar, StyleSheet, View} from 'react-native';
-// import {useStore} from 'react-redux';
-// import {ChannelList, Chat} from 'stream-chat-react-native';
-// import {ChatContext} from '../../App';
-// import {TabsGradient} from '../../components';
-// import {ChannelPreview, MessagesHeader} from '../../components/messages';
-// import {MainStackParams} from '../../routes';
-// import {RootState} from '../../store/rootReducer';
-// import EmptyContentView from '../../components/common/EmptyContentView';
-// import {
-//   LocalAttachmentType,
-//   LocalChannelType,
-//   LocalCommandType,
-//   LocalEventType,
-//   LocalMessageType,
-//   LocalReactionType,
-//   LocalUserType,
-// } from '../../types';
-// import {connectChatAccount, HeaderHeight} from '../../utils';
-// import NewChatModal from './NewChatModal';
-
-// type ChatListScreenNavigationProp = StackNavigationProp<
-//   MainStackParams,
-//   'ChatList'
-// >;
-// interface ChatListScreenProps {
-//   navigation: ChatListScreenNavigationProp;
-// }
-// /*
-//  * Screen that displays all of the user's active conversations.
-//  */
-// const ChatListScreen: React.FC<ChatListScreenProps> = () => {
-//   const {chatClient} = useContext(ChatContext);
-//   const [modalVisible, setChatModalVisible] = useState(false);
-//   const state: RootState = useStore().getState();
-//   const loggedInUserId = state.user.user.userId;
-//   const tabbarHeight = useBottomTabBarHeight();
-
-//   const memoizedFilters = useMemo(
-//     () => ({
-//       members: {$in: [loggedInUserId]},
-//       type: 'messaging',
-//     }),
-//     [],
-//   );
-
-//   const chatTheme = {
-//     channelListMessenger: {
-//       flatListContent: {
-//         backgroundColor: 'white',
-//         paddingBottom: tabbarHeight + HeaderHeight + 20,
-//       },
-//     },
-//   };
-
-//   useEffect(() => {
-//     if (loggedInUserId) {
-//       connectChatAccount(loggedInUserId, chatClient)
-//         .then((success) => {
-//           if (!success) {
-//             Alert.alert('Something wrong with chat');
-//           }
-//         })
-//         .catch((err) => {
-//           console.log('Error connecting to chat: ', err);
-//           Alert.alert('Something wrong with chat');
-//         });
-//     }
-//   }, [loggedInUserId]);
-
-//   return (
-//     <View style={styles.background}>
-//       <SafeAreaView>
-//         <StatusBar barStyle="dark-content" />
-//         <MessagesHeader
-//           createChannel={() => {
-//             setChatModalVisible(true);
-//           }}
-//         />
-//         <Chat client={chatClient} style={chatTheme}>
-//           <View style={styles.chatContainer}>
-//             <ChannelList<
-//               LocalAttachmentType,
-//               LocalChannelType,
-//               LocalCommandType,
-//               LocalEventType,
-//               LocalMessageType,
-//               LocalReactionType,
-//               LocalUserType
-//             >
-//               filters={memoizedFilters}
-//               options={{
-//                 presence: true,
-//                 state: true,
-//                 watch: true,
-//               }}
-//               sort={{last_message_at: -1}}
-//               maxUnreadCount={99}
-//               Preview={ChannelPreview}
-//               EmptyStateIndicator={() => {
-//                 return <EmptyContentView viewType={'ChatList'} />;
-//               }}
-//             />
-//           </View>
-//         </Chat>
-//         <NewChatModal {...{modalVisible, setChatModalVisible}} />
-//       </SafeAreaView>
-//       <TabsGradient />
-//     </View>
-//   );
-// };
-
-// const styles = StyleSheet.create({
-//   background: {
-//     flex: 1,
-//     backgroundColor: 'white',
-//   },
-//   container: {
-//     flex: 1,
-//     justifyContent: 'center',
-//     alignItems: 'center',
-//   },
-//   placeholder: {
-//     fontSize: 14,
-//     fontWeight: 'bold',
-//     marginBottom: 10,
-//   },
-//   button: {
-//     backgroundColor: '#CCE4FC',
-//     padding: 15,
-//     borderRadius: 5,
-//   },
-//   chatContainer: {
-//     height: '100%',
-//     marginTop: 10,
-//   },
-// });
-
-// export default ChatListScreen;
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 48724620..9326ba6a 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -15,6 +15,7 @@ import {
 } from 'react-native';
 import {MentionInput} from 'react-native-controlled-mentions';
 import {Button, normalize} from 'react-native-elements';
+import Video from 'react-native-video';
 import {useDispatch, useSelector} from 'react-redux';
 import FrontArrow from '../../assets/icons/front-arrow.svg';
 import {SearchBackground} from '../../components';
@@ -205,8 +206,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
               {...{title: moment ? moment.moment_category : title ?? ''}}
             />
             {isMediaAVideo ? (
-              // <Video uri={mediaUri} style={styles.media} />
-              <></>
+              <Video source={{uri: mediaUri}} style={styles.media} />
             ) : (
               <Image
                 style={styles.media}
-- 
cgit v1.2.3-70-g09d2


From 66dcf88ab09fbd73e234e209e270e2b31c867247 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 23 Jun 2021 17:01:42 -0400
Subject: Cleanup code, Add support for video tagging

---
 src/components/moments/Moment.tsx        |  33 ++++-----
 src/routes/main/MainStackNavigator.tsx   |   8 ++-
 src/screens/moments/TagFriendsScreen.tsx | 118 +++++++++++++++----------------
 src/screens/profile/CaptionScreen.tsx    |  92 ++++++++++++++++--------
 4 files changed, 137 insertions(+), 114 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/components/moments/Moment.tsx b/src/components/moments/Moment.tsx
index a0f66cc5..6441bca3 100644
--- a/src/components/moments/Moment.tsx
+++ b/src/components/moments/Moment.tsx
@@ -55,28 +55,19 @@ const Moment: React.FC<MomentProps> = ({
    */
   const navigateToVideoPicker = () => {
     ImagePicker.openPicker({
-      smartAlbums: [
-        'Favorites',
-        'RecentlyAdded',
-        'SelfPortraits',
-        'Screenshots',
-        'UserLibrary',
-      ],
-      width: 580,
-      height: 580,
-      cropping: false,
-      cropperToolbarTitle: 'select a video',
       mediaType: 'video',
     })
       .then(async (vid) => {
-        if ('path' in vid) {
-          let fileName = vid.filename || '';
-          if (fileName.endsWith('.heic') || fileName.endsWith('.HEIC')) {
-            fileName = fileName.split('.')[0] + '.jpg';
-          }
-          let presignedURL = await handlePresignedURL(fileName, title);
-          console.log('presigned' + JSON.stringify(presignedURL));
-          handleVideoUpload(vid, presignedURL);
+        if (vid.path) {
+          navigation.navigate('CaptionScreen', {
+            screenType,
+            title,
+            media: {
+              filename: `poc_${Math.random().toString(36).substring(7)}.mov`,
+              uri: vid.path,
+              isVideo: true,
+            },
+          });
         }
       })
       .catch((err) => {
@@ -105,11 +96,11 @@ const Moment: React.FC<MomentProps> = ({
         if (picture.path && picture.filename) {
           navigation.navigate('CaptionScreen', {
             screenType,
-            title: title,
+            title,
             media: {
               filename: picture.filename,
               uri: picture.path,
-              type: 'image',
+              isVideo: false,
             },
           });
         }
diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx
index 8157f0d7..522a18dd 100644
--- a/src/routes/main/MainStackNavigator.tsx
+++ b/src/routes/main/MainStackNavigator.tsx
@@ -37,13 +37,17 @@ export type MainStackParams = {
   };
   CaptionScreen: {
     title?: string;
-    media?: {filename: string; uri: string; type: 'image' | 'video'};
+    media?: {filename: string; uri: string; isVideo: boolean};
     screenType: ScreenType;
     selectedTags?: MomentTagType[];
     moment?: MomentType;
   };
   TagFriendsScreen: {
-    imagePath: string;
+    media: {
+      filename: string;
+      uri: string;
+      isVideo: boolean;
+    };
     selectedTags?: MomentTagType[];
   };
   TagSelectionScreen: {
diff --git a/src/screens/moments/TagFriendsScreen.tsx b/src/screens/moments/TagFriendsScreen.tsx
index 570c3776..bda38651 100644
--- a/src/screens/moments/TagFriendsScreen.tsx
+++ b/src/screens/moments/TagFriendsScreen.tsx
@@ -1,16 +1,9 @@
 import {RouteProp} from '@react-navigation/core';
 import {useNavigation} from '@react-navigation/native';
 import React, {useEffect, useRef, useState} from 'react';
-import {
-  Image,
-  Keyboard,
-  KeyboardAvoidingView,
-  Platform,
-  StyleSheet,
-  TouchableWithoutFeedback,
-  View,
-} from 'react-native';
+import {Image, StyleSheet, TouchableWithoutFeedback, View} from 'react-native';
 import {Button} from 'react-native-elements';
+import Video from 'react-native-video';
 import {MainStackParams} from 'src/routes';
 import {
   CaptionScreenHeader,
@@ -30,7 +23,7 @@ interface TagFriendsScreenProps {
   route: TagFriendsScreenRouteProps;
 }
 const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
-  const {imagePath, selectedTags} = route.params;
+  const {media, selectedTags} = route.params;
   const navigation = useNavigation();
   const imageRef = useRef(null);
   const [tags, setTags] = useState<MomentTagType[]>([]);
@@ -54,58 +47,62 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
 
   return (
     <SearchBackground>
-      <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
-        <KeyboardAvoidingView
-          behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
-          style={styles.flex}>
-          <View style={styles.contentContainer}>
-            <View style={styles.buttonsContainer}>
-              <Button
-                title="Cancel"
-                buttonStyle={styles.button}
-                onPress={() => navigation.goBack()}
-              />
-              <Button
-                title="Done"
-                titleStyle={styles.shareButtonTitle}
-                buttonStyle={styles.button}
-                onPress={handleDone}
+      <View style={styles.contentContainer}>
+        <View style={styles.buttonsContainer}>
+          <Button
+            title="Cancel"
+            buttonStyle={styles.button}
+            onPress={() => navigation.goBack()}
+          />
+          <Button
+            title="Done"
+            titleStyle={styles.shareButtonTitle}
+            buttonStyle={styles.button}
+            onPress={handleDone}
+          />
+        </View>
+        <CaptionScreenHeader
+          style={styles.header}
+          title={'Tap on photo to tag friends!'}
+        />
+        <TouchableWithoutFeedback
+          onPress={() =>
+            navigation.navigate('TagSelectionScreen', {
+              selectedTags: tags,
+            })
+          }>
+          {media.isVideo ? (
+            <View style={styles.media} ref={imageRef}>
+              <Video
+                style={styles.media}
+                source={{uri: media.uri}}
+                repeat={true}
               />
             </View>
-            <CaptionScreenHeader
-              style={styles.header}
-              title={'Tap on photo to tag friends!'}
+          ) : (
+            <Image
+              ref={imageRef}
+              style={styles.media}
+              source={{uri: media.uri}}
+              resizeMode={'cover'}
             />
-            <TouchableWithoutFeedback
-              onPress={() =>
-                navigation.navigate('TagSelectionScreen', {
-                  selectedTags: tags,
-                })
-              }>
-              <Image
-                ref={imageRef}
-                style={styles.image}
-                source={{uri: imagePath}}
-                resizeMode={'cover'}
-              />
-            </TouchableWithoutFeedback>
-            {tags.length !== 0 && (
-              <MomentTags
-                tags={tags}
-                setTags={setTags}
-                editing={true}
-                imageRef={imageRef}
-                deleteFromList={(user) =>
-                  setTags(tags.filter((tag) => tag.user.id !== user.id))
-                }
-              />
-            )}
-            <View style={styles.footerContainer}>
-              <TagFriendsFooter tags={tags} setTags={setTags} />
-            </View>
-          </View>
-        </KeyboardAvoidingView>
-      </TouchableWithoutFeedback>
+          )}
+        </TouchableWithoutFeedback>
+        {tags.length !== 0 && (
+          <MomentTags
+            tags={tags}
+            setTags={setTags}
+            editing={true}
+            imageRef={imageRef}
+            deleteFromList={(user) =>
+              setTags(tags.filter((tag) => tag.user.id !== user.id))
+            }
+          />
+        )}
+        <View style={styles.footerContainer}>
+          <TagFriendsFooter tags={tags} setTags={setTags} />
+        </View>
+      </View>
     </SearchBackground>
   );
 };
@@ -113,7 +110,6 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
 const styles = StyleSheet.create({
   contentContainer: {
     paddingTop: StatusBarHeight,
-    justifyContent: 'flex-end',
   },
   buttonsContainer: {
     flexDirection: 'row',
@@ -131,7 +127,7 @@ const styles = StyleSheet.create({
   header: {
     marginVertical: 20,
   },
-  image: {
+  media: {
     position: 'relative',
     width: SCREEN_WIDTH,
     aspectRatio: 1,
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 9326ba6a..1b96face 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -28,7 +28,13 @@ import {
   SUCCESS_PIC_UPLOAD,
 } from '../../constants/strings';
 import {MainStackParams} from '../../routes';
-import {patchMoment, postMoment, postMomentTags} from '../../services';
+import {
+  handlePresignedURL,
+  handleVideoUpload,
+  patchMoment,
+  postMoment,
+  postMomentTags,
+} from '../../services';
 import {
   loadUserMoments,
   updateProfileCompletionStage,
@@ -73,7 +79,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
         moment.moment_url.endsWith('.png') ||
         moment.moment_url.endsWith('.PNG')
       )
-    : route.params.media?.type === 'video';
+    : route.params.media?.isVideo ?? false;
 
   useEffect(() => {
     setTags(selectedTags ? selectedTags : []);
@@ -133,35 +139,57 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
   const handleShare = async () => {
     setLoading(true);
     if (moment || !mediaFilename || !title) {
-      return;
-    }
-    const momentResponse = await postMoment(
-      mediaFilename,
-      mediaUri,
-      caption,
-      title,
-      userId,
-    );
-    if (!momentResponse) {
       handleFailed();
       return;
     }
-    const momentTagResponse = await postMomentTags(
-      momentResponse.moment_id,
-      formattedTags(),
-    );
-    if (!momentTagResponse) {
-      handleFailed();
-      return;
+    let profileCompletionStage;
+    let momentId;
+    // separate upload logic for image/video
+    if (isMediaAVideo) {
+      const presignedURL = await handlePresignedURL(mediaFilename, title);
+      // TOOD: ignoring type error for PoC reason
+      const response: {
+        response_msg: string;
+        response_url: string;
+        moment_id: string;
+      } = handleVideoUpload(
+        {
+          filename: mediaFilename,
+          sourceURL: mediaUri,
+        },
+        presignedURL,
+      );
+      momentId = response.moment_id;
+    } else {
+      const momentResponse = await postMoment(
+        mediaFilename,
+        mediaUri,
+        caption,
+        title,
+        userId,
+      );
+      if (!momentResponse) {
+        handleFailed();
+        return;
+      }
+      profileCompletionStage = momentResponse.profile_completion_stage;
+      momentId = momentResponse.moment_id;
+    }
+    if (momentId) {
+      const momentTagResponse = await postMomentTags(momentId, formattedTags());
+      if (!momentTagResponse) {
+        handleFailed();
+        return;
+      }
     }
     dispatch(loadUserMoments(userId));
-    dispatch(
-      updateProfileCompletionStage(momentResponse.profile_completion_stage),
-    );
+    if (profileCompletionStage) {
+      dispatch(updateProfileCompletionStage(profileCompletionStage));
+    }
     handleSuccess();
   };
 
-  const handleDone = async () => {
+  const handleDoneEditing = async () => {
     setLoading(true);
     if (moment?.moment_id) {
       const success = await patchMoment(
@@ -198,7 +226,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
                 title={moment ? 'Done' : 'Share'}
                 titleStyle={styles.shareButtonTitle}
                 buttonStyle={styles.button}
-                onPress={moment ? handleDone : handleShare}
+                onPress={moment ? handleDoneEditing : handleShare}
               />
             </View>
             <CaptionScreenHeader
@@ -206,7 +234,11 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
               {...{title: moment ? moment.moment_category : title ?? ''}}
             />
             {isMediaAVideo ? (
-              <Video source={{uri: mediaUri}} style={styles.media} />
+              <Video
+                style={styles.media}
+                source={{uri: mediaUri}}
+                repeat={true}
+              />
             ) : (
               <Image
                 style={styles.media}
@@ -225,11 +257,11 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
             <TouchableOpacity
               onPress={() =>
                 navigation.navigate('TagFriendsScreen', {
-                  imagePath: moment
-                    ? moment.moment_url
-                    : media
-                    ? media.uri
-                    : '',
+                  media: {
+                    filename: mediaFilename ?? '',
+                    uri: mediaUri,
+                    isVideo: isMediaAVideo,
+                  },
                   selectedTags: tags,
                 })
               }
-- 
cgit v1.2.3-70-g09d2


From 9f835e1b82647477ec959a62b02dee4e9351b1b5 Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 23 Jun 2021 17:08:31 -0400
Subject: Clean up video upload logic

---
 src/screens/profile/CaptionScreen.tsx | 20 +++++++-------------
 src/services/MomentService.ts         |  5 ++---
 src/types/types.ts                    |  1 +
 3 files changed, 10 insertions(+), 16 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 1b96face..d53570cb 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -147,19 +147,13 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
     // separate upload logic for image/video
     if (isMediaAVideo) {
       const presignedURL = await handlePresignedURL(mediaFilename, title);
-      // TOOD: ignoring type error for PoC reason
-      const response: {
-        response_msg: string;
-        response_url: string;
-        moment_id: string;
-      } = handleVideoUpload(
-        {
-          filename: mediaFilename,
-          sourceURL: mediaUri,
-        },
-        presignedURL,
-      );
-      momentId = response.moment_id;
+      if (!presignedURL) {
+        handleFailed();
+        return;
+      }
+      momentId = presignedURL.moment_id;
+      // TODO: assume success for now
+      await handleVideoUpload(mediaFilename, mediaUri, presignedURL);
     } else {
       const momentResponse = await postMoment(
         mediaFilename,
diff --git a/src/services/MomentService.ts b/src/services/MomentService.ts
index da1bfb97..ca32a3f3 100644
--- a/src/services/MomentService.ts
+++ b/src/services/MomentService.ts
@@ -311,7 +311,7 @@ export const handleVideoUpload = async (
     // let data = await response.json();
     if (status === 200 || status === 204) {
       console.log('complete');
-      return response;
+      return true;
     } else {
       if (status === 404) {
         console.log(
@@ -323,11 +323,10 @@ export const handleVideoUpload = async (
         console.log(ERROR_SOMETHING_WENT_WRONG_REFRESH);
       }
       console.log(response);
-      return false;
     }
   } catch (error) {
     console.log(error);
     console.log(ERROR_SOMETHING_WENT_WRONG);
-    return false;
   }
+  return false;
 };
diff --git a/src/types/types.ts b/src/types/types.ts
index f6f23fc8..416d9146 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -379,4 +379,5 @@ export type PresignedURLResponse = {
       'x-amz-signature': string;
     };
   };
+  moment_id: string;
 };
-- 
cgit v1.2.3-70-g09d2


From a8c210165938cfa4da7ed6bc185af297d528d2aa Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Wed, 30 Jun 2021 15:32:52 -0400
Subject: Remove filename requirement for all moment upload

---
 src/components/comments/ZoomInCropper.tsx | 17 +++++++++++++++--
 src/components/moments/Moment.tsx         |  2 --
 src/routes/main/MainStackNavigator.tsx    |  5 ++---
 src/screens/moments/CameraScreen.tsx      | 18 +++++++++++++++---
 src/screens/profile/CaptionScreen.tsx     | 16 ++++------------
 src/services/MomentService.ts             | 21 +++++++--------------
 6 files changed, 43 insertions(+), 36 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/components/comments/ZoomInCropper.tsx b/src/components/comments/ZoomInCropper.tsx
index cfd3cbbc..7fa88f6e 100644
--- a/src/components/comments/ZoomInCropper.tsx
+++ b/src/components/comments/ZoomInCropper.tsx
@@ -1,6 +1,7 @@
 import {RouteProp} from '@react-navigation/core';
+import {useFocusEffect} from '@react-navigation/native';
 import {StackNavigationProp} from '@react-navigation/stack';
-import React, {useEffect, useState} from 'react';
+import 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';
@@ -33,6 +34,19 @@ export const ZoomInCropper: React.FC<ZoomInCropperProps> = ({
   const [y0, setY0] = useState<number>();
   const [y1, setY1] = useState<number>();
 
+  useFocusEffect(
+    useCallback(() => {
+      navigation.dangerouslyGetParent()?.setOptions({
+        tabBarVisible: false,
+      });
+      return () => {
+        navigation.dangerouslyGetParent()?.setOptions({
+          tabBarVisible: true,
+        });
+      };
+    }, [navigation]),
+  );
+
   // Setting original aspect ratio of image
   useEffect(() => {
     if (media.uri) {
@@ -65,7 +79,6 @@ export const ZoomInCropper: React.FC<ZoomInCropperProps> = ({
             screenType,
             title: title,
             media: {
-              filename: media.filename,
               uri: croppedURL,
               isVideo: false,
             },
diff --git a/src/components/moments/Moment.tsx b/src/components/moments/Moment.tsx
index f057b329..50c60fd9 100644
--- a/src/components/moments/Moment.tsx
+++ b/src/components/moments/Moment.tsx
@@ -44,12 +44,10 @@ const Moment: React.FC<MomentProps> = ({
   const navigation = useNavigation();
 
   const navigateToCaptionScreenForVideo = (uri: string) => {
-    const randHash = Math.random().toString(36).substring(7);
     navigation.navigate('CaptionScreen', {
       screenType,
       title,
       media: {
-        filename: `poc_${randHash}.mov`,
         uri,
         isVideo: true,
       },
diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx
index 21430d7a..a5d73988 100644
--- a/src/routes/main/MainStackNavigator.tsx
+++ b/src/routes/main/MainStackNavigator.tsx
@@ -37,14 +37,13 @@ export type MainStackParams = {
   };
   CaptionScreen: {
     title?: string;
-    media?: {filename: string; uri: string; isVideo: boolean};
+    media?: {uri: string; isVideo: boolean};
     screenType: ScreenType;
     selectedTags?: MomentTagType[];
     moment?: MomentType;
   };
   TagFriendsScreen: {
     media: {
-      filename: string;
       uri: string;
       isVideo: boolean;
     };
@@ -111,7 +110,7 @@ export type MainStackParams = {
   Chat: undefined;
   NewChatModal: undefined;
   ZoomInCropper: {
-    media: {filename: string; uri: string; isVideo: boolean};
+    media: {uri: string; isVideo: boolean};
     screenType: ScreenType;
     title: string;
   };
diff --git a/src/screens/moments/CameraScreen.tsx b/src/screens/moments/CameraScreen.tsx
index b3275764..104774c0 100644
--- a/src/screens/moments/CameraScreen.tsx
+++ b/src/screens/moments/CameraScreen.tsx
@@ -1,8 +1,9 @@
 import CameraRoll from '@react-native-community/cameraroll';
 import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
 import {RouteProp} from '@react-navigation/core';
+import {useFocusEffect} from '@react-navigation/native';
 import {StackNavigationProp} from '@react-navigation/stack';
-import React, {createRef, useEffect, useState} from 'react';
+import React, {createRef, useCallback, useEffect, useState} from 'react';
 import {StyleSheet, TouchableOpacity, View} from 'react-native';
 import {CameraType, FlashMode, RNCamera} from 'react-native-camera';
 import CloseIcon from '../../assets/ionicons/close-outline.svg';
@@ -36,6 +37,19 @@ const CameraScreen: React.FC<CameraScreenProps> = ({route, navigation}) => {
   const [mostRecentPhoto, setMostRecentPhoto] = useState<string>('');
   const [showSaveButton, setShowSaveButton] = useState<boolean>(false);
 
+  useFocusEffect(
+    useCallback(() => {
+      navigation.dangerouslyGetParent()?.setOptions({
+        tabBarVisible: false,
+      });
+      return () => {
+        navigation.dangerouslyGetParent()?.setOptions({
+          tabBarVisible: true,
+        });
+      };
+    }, [navigation]),
+  );
+
   /*
    *  Chooses the last picture from gallery to display as the gallery button icon
    */
@@ -61,7 +75,6 @@ const CameraScreen: React.FC<CameraScreenProps> = ({route, navigation}) => {
       screenType,
       title,
       media: {
-        filename: 'dont have that info',
         uri: capturedImage,
         isVideo: false, // TODO: false for now
       },
@@ -131,7 +144,6 @@ const CameraScreen: React.FC<CameraScreenProps> = ({route, navigation}) => {
                       screenType,
                       title,
                       media: {
-                        filename: pic.filename,
                         uri: pic.path,
                         isVideo: false,
                       },
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 364b81a3..da3efb06 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -69,7 +69,6 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
     selectedTags ? selectedTags : [],
   );
   const [taggedList, setTaggedList] = useState<string>('');
-  const mediaFilename = moment ? undefined : route.params.media!.filename;
   const mediaUri = moment ? moment.moment_url : route.params.media!.uri;
   // TODO: change this once moment refactor is done
   const isMediaAVideo = moment
@@ -138,7 +137,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
 
   const handleShare = async () => {
     setLoading(true);
-    if (moment || !mediaFilename || !title) {
+    if (moment || !title) {
       handleFailed();
       return;
     }
@@ -146,22 +145,16 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
     let momentId;
     // separate upload logic for image/video
     if (isMediaAVideo) {
-      const presignedURL = await handlePresignedURL(mediaFilename, title);
+      const presignedURL = await handlePresignedURL(title);
       if (!presignedURL) {
         handleFailed();
         return;
       }
       momentId = presignedURL.moment_id;
       // TODO: assume success for now
-      await handleVideoUpload(mediaFilename, mediaUri, presignedURL);
+      await handleVideoUpload(mediaUri, presignedURL);
     } else {
-      const momentResponse = await postMoment(
-        mediaFilename,
-        mediaUri,
-        caption,
-        title,
-        userId,
-      );
+      const momentResponse = await postMoment(mediaUri, caption, title, userId);
       if (!momentResponse) {
         handleFailed();
         return;
@@ -252,7 +245,6 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
               onPress={() =>
                 navigation.navigate('TagFriendsScreen', {
                   media: {
-                    filename: mediaFilename ?? '',
                     uri: mediaUri,
                     isVideo: isMediaAVideo,
                   },
diff --git a/src/services/MomentService.ts b/src/services/MomentService.ts
index b274ef04..ad0b0042 100644
--- a/src/services/MomentService.ts
+++ b/src/services/MomentService.ts
@@ -6,6 +6,7 @@ import {
   MOMENT_TAGS_ENDPOINT,
   MOMENT_THUMBNAIL_ENDPOINT,
   PRESIGNED_URL_ENDPOINT,
+  RADIO_BUTTON_GREY,
   TAGG_CUSTOMER_SUPPORT,
 } from '../constants';
 import {
@@ -16,7 +17,6 @@ import {MomentPostType, MomentTagType, PresignedURLResponse} from '../types';
 import {checkImageUploadStatus} from '../utils';
 
 export const postMoment = async (
-  fileName: string,
   uri: string,
   caption: string,
   category: string,
@@ -25,13 +25,9 @@ export const postMoment = async (
   try {
     const request = new FormData();
 
-    //Manipulating filename to end with .jpg instead of .heic
-    if (fileName.endsWith('.heic') || fileName.endsWith('.HEIC')) {
-      fileName = fileName.split('.')[0] + '.jpg';
-    }
     request.append('image', {
       uri: uri,
-      name: fileName,
+      name: 'moment.jpg', // we don't care about filename, anything works
       type: 'image/jpg',
     });
     request.append('moment', category);
@@ -219,14 +215,13 @@ export const deleteMomentTag = async (moment_tag_id: string) => {
  * This function makes a request to the server in order to provide the client with a presigned URL.
  * This is called first, in order for the client to directly upload a file to S3
  * @param value: string | undefined
- * @param filename: string | undefined
  * @returns a PresignedURLResponse object
  */
-export const handlePresignedURL = async (
-  filename: string | undefined,
-  momentCategory: string,
-) => {
+export const handlePresignedURL = async (momentCategory: string) => {
   try {
+    // TODO: just a random filename for video poc, we should not need to once complete
+    const randHash = Math.random().toString(36).substring(7);
+    const filename = `[pc_${randHash}].mov`;
     const token = await AsyncStorage.getItem('token');
     const response = await fetch(PRESIGNED_URL_ENDPOINT, {
       method: 'POST',
@@ -260,13 +255,11 @@ export const handlePresignedURL = async (
 /**
  * This util function takes in the file object and the PresignedURLResponse object, creates form data from the latter,
  * and makes a post request to the presigned URL, sending the file object inside of the form data.
- * @param filename: the filename
  * @param filePath: the path to the file, including filename
  * @param urlObj  PresignedURLResponse | undefined
  * @returns responseURL or boolean
  */
 export const handleVideoUpload = async (
-  filename: string,
   filePath: string,
   urlObj: PresignedURLResponse | undefined,
 ) => {
@@ -297,7 +290,7 @@ export const handleVideoUpload = async (
       uri: filePath,
       // other types such as 'quicktime' 'image' etc exist, and we can programmatically type this, but for now sticking with simple 'video'
       type: 'video',
-      name: filename,
+      name: 'moment.mov', // we don't care about filename, anything works
     });
     const response = await fetch(urlObj.response_url.url, {
       method: 'POST',
-- 
cgit v1.2.3-70-g09d2


From 29f64921943fb7016ab0db79e4c06377d617a3bf Mon Sep 17 00:00:00 2001
From: Ivan Chen <ivan@tagg.id>
Date: Thu, 1 Jul 2021 15:53:25 -0400
Subject: Add logic for handling new video upload handshake

---
 src/screens/profile/CaptionScreen.tsx | 14 +++++++++-----
 src/services/MomentService.ts         |  2 +-
 2 files changed, 10 insertions(+), 6 deletions(-)

(limited to 'src/screens/profile/CaptionScreen.tsx')

diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index da3efb06..05db8ed7 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -145,14 +145,18 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
     let momentId;
     // separate upload logic for image/video
     if (isMediaAVideo) {
-      const presignedURL = await handlePresignedURL(title);
-      if (!presignedURL) {
+      const presignedURLResponse = await handlePresignedURL(title);
+      if (!presignedURLResponse) {
         handleFailed();
         return;
       }
-      momentId = presignedURL.moment_id;
-      // TODO: assume success for now
-      await handleVideoUpload(mediaUri, presignedURL);
+      momentId = presignedURLResponse.moment_id;
+      const fileHash = presignedURLResponse.response_url.fields.key;
+      if (fileHash !== null && fileHash !== '' && fileHash !== undefined) {
+        await handleVideoUpload(mediaUri, presignedURLResponse);
+      } else {
+        handleFailed();
+      }
     } else {
       const momentResponse = await postMoment(mediaUri, caption, title, userId);
       if (!momentResponse) {
diff --git a/src/services/MomentService.ts b/src/services/MomentService.ts
index 9e853a49..87bdfa40 100644
--- a/src/services/MomentService.ts
+++ b/src/services/MomentService.ts
@@ -289,7 +289,7 @@ export const handleVideoUpload = async (
       uri: filePath,
       // other types such as 'quicktime' 'image' etc exist, and we can programmatically type this, but for now sticking with simple 'video'
       type: 'video',
-      name: 'moment.mov', // we don't care about filename, anything works
+      name: urlObj.response_url.fields.key,
     });
     const response = await fetch(urlObj.response_url.url, {
       method: 'POST',
-- 
cgit v1.2.3-70-g09d2

