Created
October 9, 2023 12:04
-
-
Save tanner-west/d71cb11e95651bcc5540eda85b1f73a2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useRef, useMemo, useState } from "react"; | |
import { | |
Image, | |
useWindowDimensions, | |
View, | |
Text, | |
TouchableOpacity, | |
FlatList, | |
} from "react-native"; | |
import MaterialIcons from "@expo/vector-icons/MaterialCommunityIcons"; | |
import BottomSheet, { BottomSheetTextInput } from "@gorhom/bottom-sheet"; | |
import { Video, ResizeMode } from "expo-av"; | |
import Animated, { | |
useSharedValue, | |
withTiming, | |
useAnimatedStyle, | |
withSequence, | |
FadeIn, | |
} from "react-native-reanimated"; | |
import { LinearGradient } from "expo-linear-gradient"; | |
const ActionIcon = ({ | |
name, | |
action, | |
liked, | |
disliked, | |
}: { | |
name: | |
| "thumb-up" | |
| "thumb-down" | |
| "thumb-up-outline" | |
| "thumb-down-outline" | |
| "comment" | |
| "share"; | |
action?: () => void; | |
liked?: boolean; | |
disliked?: boolean; | |
}) => { | |
return ( | |
<TouchableOpacity onPress={action} style={{ marginTop: 20 }}> | |
<MaterialIcons | |
name={name} | |
color={disliked ? "#6173ff" : liked ? "#6173ff" : "white"} | |
style={{ shadowColor: "black", shadowRadius: 15, shadowOpacity: 0.75 }} | |
size={40} | |
/> | |
</TouchableOpacity> | |
); | |
}; | |
const reels = [ | |
{ | |
source: require(`../assets/videos/waves.mp4`), | |
title: "On a boat", | |
tags: ["summervibes", "ocean", "cool"], | |
profilePic: require(`../assets/images/faces/humans/face_0.png`), | |
profileName: "chattanooga_chuck", | |
}, | |
{ | |
source: require(`../assets/videos/friends.mp4`), | |
title: "Besties 4 Eva", | |
tags: ["friends", "love", "feels"], | |
profilePic: require(`../assets/images/faces/humans/face_2.png`), | |
profileName: "sabrina28288", | |
}, | |
{ | |
source: require(`../assets/videos/read.mp4`), | |
title: "I read 400 books and this is what happened", | |
tags: ["text", "readingiscool", "smart"], | |
profilePic: require(`../assets/images/faces/humans/face_1.png`), | |
profileName: "reader_rita", | |
}, | |
{ | |
source: require(`../assets/videos/doughnuts.mp4`), | |
title: "I ate the whole box 😏", | |
tags: ["dough", "yeast", "sprinkleeees"], | |
profilePic: require(`../assets/images/faces/humans/face_3.png`), | |
profileName: "bakedgoodsaddict", | |
comments: [ | |
{ | |
text: "Looks great 😍😍😍", | |
pic: require(`../assets/images/faces/humans/face_12.png`), | |
profileName: "lovedough4673 | 2d", | |
}, | |
{ | |
text: "Yummmmmmmmm", | |
pic: require(`../assets/images/faces/humans/face_9.png`), | |
profileName: "jimbo | 1h", | |
}, | |
{ | |
text: "🍩🍩🍩🍩🍩 i would eat them all 🍩🍩🍩🍩", | |
pic: require(`../assets/images/faces/humans/face_10.png`), | |
profileName: "sarah_k | 12h", | |
}, | |
{ | |
text: "WHERE CAN I GET SOME???", | |
pic: require(`../assets/images/faces/humans/face_15.png`), | |
profileName: "amara_z | 1d", | |
}, | |
{ | |
text: "💯💯💯💯💯💯💯💯", | |
pic: require(`../assets/images/faces/humans/face_7.png`), | |
profileName: "jboss | 30m", | |
}, | |
], | |
}, | |
{ | |
source: require(`../assets/videos/door.mp4`), | |
title: "Let me sell your house!!!", | |
tags: ["moving", "real_estate", "houses"], | |
profilePic: require(`../assets/images/faces/humans/face_8.png`), | |
profileName: "dream_team_trina", | |
}, | |
{ | |
source: require(`../assets/videos/beans.mp4`), | |
title: "Beans", | |
tags: ["fresh", "barista", "gourmet"], | |
profilePic: require(`../assets/images/faces/humans/face_7.png`), | |
profileName: "thejoe", | |
}, | |
{ | |
source: require(`../assets/videos/bake.mp4`), | |
title: "Ready, set, bake!", | |
tags: ["breadweek", "proof", "rise"], | |
profilePic: require(`../assets/images/faces/humans/face_16.png`), | |
profileName: "iwatchsports", | |
}, | |
]; | |
const Reel = ({ item }) => { | |
const { source, title, tags, comments, profilePic, profileName } = item; | |
const [liked, setLiked] = useState(false); | |
const [disliked, setDisliked] = useState(false); | |
const [myComment, setMyComment] = useState(""); | |
const [myCommentEditing, setMyCommentEditing] = useState(""); | |
const window = useWindowDimensions(); | |
const bottomSheetRef = useRef<BottomSheet>(null); | |
const videoRef = useRef<Video>(null); | |
const snapPoints = useMemo(() => ["25%", "50%"], []); | |
const rotation = useSharedValue(0); | |
const translateY = useSharedValue(0); | |
const opacity = useSharedValue(1); | |
const rotationYThumbsDown = useSharedValue(0); | |
const translateYThumbsDown = useSharedValue(0); | |
const opacityThumbsDown = useSharedValue(1); | |
const onPressThumbsUp = () => { | |
if (!liked) { | |
rotation.value = withSequence( | |
withTiming(-45, { duration: 150 }), | |
withTiming(0, { duration: 150 }), | |
withTiming(0, { duration: 0 }) | |
); | |
translateY.value = withSequence( | |
withTiming(-50, { duration: 150 }), | |
withTiming(0, { duration: 150 }), | |
withTiming(-500, { duration: 500 }), | |
withTiming(0, { duration: 0 }) | |
); | |
opacity.value = withSequence( | |
withTiming(1, { duration: 200 }), | |
withTiming(0, { duration: 500 }), | |
withTiming(1, { duration: 250 }) | |
); | |
setTimeout(() => setLiked(true), 500); | |
setDisliked(false); | |
} else { | |
setLiked(false); | |
} | |
}; | |
const onPressThumbsDown = () => { | |
if (!disliked) { | |
rotationYThumbsDown.value = withSequence( | |
withTiming(-90, { duration: 500 }), | |
withTiming(0, { duration: 0 }) | |
); | |
translateYThumbsDown.value = withSequence( | |
withTiming(50, { duration: 500 }), | |
withTiming(0, { duration: 0 }) | |
); | |
opacityThumbsDown.value = withSequence( | |
withTiming(0, { duration: 500 }), | |
withTiming(1, { duration: 250 }) | |
); | |
setTimeout(() => setDisliked(true), 500); | |
setLiked(false); | |
} else { | |
setDisliked(false); | |
} | |
}; | |
const animatedStyleThumbsUp = useAnimatedStyle(() => { | |
return { | |
transform: [ | |
{ rotate: `${rotation.value}deg` }, | |
{ translateY: translateY.value }, | |
], | |
opacity: opacity.value, | |
}; | |
}); | |
const animatedStyleThumbsDown = useAnimatedStyle(() => { | |
return { | |
transform: [ | |
{ rotateY: `${rotationYThumbsDown.value}deg` }, | |
{ translateY: translateYThumbsDown.value }, | |
], | |
opacity: opacityThumbsDown.value, | |
}; | |
}); | |
const openBottomSheet = () => { | |
bottomSheetRef.current?.snapToIndex(1); | |
}; | |
return ( | |
<View style={{ width: window.width, height: window.height }}> | |
<Video | |
ref={videoRef} | |
style={{ width: window.width, height: window.height }} | |
source={source} | |
resizeMode={ResizeMode.COVER} | |
isLooping | |
shouldPlay | |
rate={2} | |
/> | |
<LinearGradient | |
style={{ | |
height: window.height / 2, | |
width: window.width, | |
position: "absolute", | |
bottom: 0, | |
}} | |
colors={["transparent", "rgba(0,0,0,0.8)"]} | |
/> | |
<View | |
style={{ | |
width: window.width, | |
position: "absolute", | |
left: 0, | |
bottom: 50, | |
paddingHorizontal: 10, | |
}} | |
> | |
<View | |
style={{ | |
flexDirection: "row", | |
justifyContent: "flex-start", | |
alignItems: "center", | |
}} | |
> | |
<Image | |
source={profilePic} | |
style={{ | |
maxHeight: 30, | |
maxWidth: 30, | |
marginRight: 10, | |
marginBottom: 10, | |
borderColor: "white", | |
borderWidth: 2, | |
borderRadius: 15, | |
}} | |
resizeMode={"contain"} | |
/> | |
<Text style={{ fontSize: 18, color: "white", marginBottom: 5 }}> | |
{profileName} | |
</Text> | |
</View> | |
<Text style={{ fontSize: 18, color: "white", marginBottom: 5 }}> | |
{title} | |
</Text> | |
<Text style={{ fontSize: 18, color: "white", fontWeight: "bold" }}> | |
{"#" + tags.join(" #")} | |
</Text> | |
</View> | |
<View | |
style={{ | |
height: window.height, | |
position: "absolute", | |
right: 10, | |
justifyContent: "center", | |
alignItems: "center", | |
padding: 5, | |
}} | |
> | |
<Animated.View style={[animatedStyleThumbsUp]}> | |
{liked ? ( | |
<ActionIcon | |
name="thumb-up" | |
action={onPressThumbsUp} | |
disliked={liked} | |
/> | |
) : ( | |
<ActionIcon name="thumb-up-outline" action={onPressThumbsUp} /> | |
)} | |
</Animated.View> | |
<Animated.View style={[animatedStyleThumbsDown]}> | |
{disliked ? ( | |
<ActionIcon | |
name="thumb-down" | |
action={onPressThumbsDown} | |
disliked={disliked} | |
/> | |
) : ( | |
<ActionIcon name="thumb-down-outline" action={onPressThumbsDown} /> | |
)} | |
</Animated.View> | |
<ActionIcon name="comment" action={openBottomSheet} /> | |
<ActionIcon name="share" /> | |
</View> | |
<BottomSheet | |
snapPoints={snapPoints} | |
index={-1} | |
enablePanDownToClose | |
ref={bottomSheetRef} | |
keyboardBehavior="interactive" | |
keyboardBlurBehavior="restore" | |
> | |
<View style={{ padding: 10 }}> | |
{myComment && ( | |
<Animated.View | |
entering={FadeIn.duration(1000)} | |
style={{ | |
flexDirection: "row", | |
marginBottom: 20, | |
alignItems: "center", | |
}} | |
> | |
<Image | |
source={require(`../assets/images/faces/humans/face_9.png`)} | |
style={{ maxHeight: 20, maxWidth: 20 }} | |
resizeMode="contain" | |
/> | |
<View style={{ marginLeft: 5 }}> | |
<Text | |
style={{ fontSize: 12, fontWeight: "bold", marginBottom: 2 }} | |
> | |
{"reelz_lover"} | |
</Text> | |
<Text>{myComment}</Text> | |
</View> | |
</Animated.View> | |
)} | |
{comments?.map(({ text, pic, profileName }) => ( | |
<View | |
key={text} | |
style={{ | |
flexDirection: "row", | |
marginBottom: 20, | |
alignItems: "center", | |
}} | |
> | |
<Image | |
source={pic} | |
style={{ maxHeight: 20, maxWidth: 20 }} | |
resizeMode="contain" | |
/> | |
<View style={{ marginLeft: 5 }}> | |
<Text | |
style={{ fontSize: 12, fontWeight: "bold", marginBottom: 2 }} | |
> | |
{profileName} | |
</Text> | |
<Text>{text}</Text> | |
</View> | |
</View> | |
))} | |
<View style={{ flexDirection: "row" }}> | |
<Image | |
source={require(`../assets/images/faces/humans/face_9.png`)} | |
style={{ maxWidth: 50, maxHeight: 50 }} | |
/> | |
<BottomSheetTextInput | |
style={{ | |
flex: 1, | |
borderColor: "lightgray", | |
borderWidth: 1, | |
borderRadius: 10, | |
padding: 5, | |
margin: 5, | |
}} | |
placeholder="How do you feel about it?" | |
returnKeyLabel="Send It" | |
returnKeyType="send" | |
value={myCommentEditing} | |
onChangeText={(text) => setMyCommentEditing(text)} | |
onSubmitEditing={({ nativeEvent }) => { | |
setMyComment(nativeEvent.text); | |
setMyCommentEditing(""); | |
}} | |
/> | |
</View> | |
</View> | |
</BottomSheet> | |
</View> | |
); | |
}; | |
const Reelz = () => { | |
return ( | |
<View style={{ flex: 1, backgroundColor: "black" }}> | |
<FlatList | |
pagingEnabled | |
data={reels} | |
renderItem={({ item, index }) => <Reel key={item.title} item={item} />} | |
scrollEventThrottle={1} | |
decelerationRate={"fast"} | |
/> | |
</View> | |
); | |
}; | |
export default Reelz; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment