What I'm I doing wrong with my custom video controls

25 Views Asked by At

I am trying to create custom video controls for my react native app but it seems like I am missing something. Currently only the pause/play functionality work. The fast forward/ rewinding and slider don't work. Here is the code for the pause and play functionality that works.

const togglePlayPause = async () => {
        if (videoRef.current) {
          if (isPlaying) {
            await videoRef.current.pauseAsync();
          } else {
            await videoRef.current.playAsync();
          }
          setIsPlaying(!isPlaying);
        }
      };

<View style={styles.controls}>
            <TouchableOpacity onPress={togglePlayPause} style={styles.controlButton}>
                {isPlaying?
                <FontAwesome5 name="pause" size={30} color="white" />
                :
                <FontAwesome5 name="play" size={30} color="white" />
                }
            </TouchableOpacity>
      </View>

I think I did the right thing but it's not working so probably not. Could someone tell me what I am doing wrong? This is the rest of the code including the pause and play functionally I mentioned earlier

import { View, Text,Dimensions, ImageBackground,StyleSheet, StatusBar, FlatList,Image, TouchableOpacity } from 'react-native'
import { TapGestureHandler, State } from 'react-native-gesture-handler';
import { FontAwesome5 } from '@expo/vector-icons';
import Slider from '@react-native-community/slider';
import React,{useState,useEffect,useRef} from 'react'
import EchoIcon from './Echo';
import ThumbsDownIcon from './ThumbsDown';
import ThumbsUpIcon from './ThumbsUp';
import { Video,ResizeMode } from 'expo-av';
import { supabase } from '../../../../supabase1';
import CommentThumbsUp from '../../../../animations/CommentThumbsUp';
import CommentThumbsDown from '../../../../animations/CommentThumbsDown';

export default function ViewPostMedia({navigation,route}) {
    const screenWidth = Dimensions.get('window').width;
    const SCREEN_HEIGHT = (Dimensions.get('window').height)
    const {media} =route.params;
    const {postID} = route.params;
    const {initialLikes} = route.params
    const {initialDislikes} = route.params
    const {initialEchoes} = route.params
    const {mediaType} = route.params
    const [Comments, setComments] = useState([])
    const videoRef = useRef(null);
    const [isPlaying, setIsPlaying] = useState(false);
    const [sliderValue, setSliderValue] = useState(0);
    const [videoDuration, setVideoDuration] = useState(0);
    const [sliderBeingDragged, setSliderBeingDragged] = useState(false);
    const [doubleTapRight, setDoubleTapRight] = useState(false);
    const [doubleTapLeft, setDoubleTapLeft] = useState(false);

    
    

    useEffect(() => {
      const getVideoDuration = async () => {
        if (videoRef.current) {
          const { durationMillis } = await videoRef.current.getStatusAsync();
          console.log('Video duration:', durationMillis / 1000);
          setVideoDuration(durationMillis / 1000); 
        }
      };

      getVideoDuration();
    }, [videoRef.current]);

    // Update slider position based on video progress
    useEffect(() => {
      const updateSliderPosition = () => {
        if (videoRef.current) {
          videoRef.current.getStatusAsync().then((status) => {
            const { positionMillis, durationMillis } = status;
            const currentPosition = positionMillis / 1000; 
            const progress = currentPosition / (durationMillis / 1000);
            setSliderValue(progress);
          });
        }
      };

      const intervalId = setInterval(updateSliderPosition, 1000); // Update every second

      return () => clearInterval(intervalId); // Clean up interval
    }, [videoRef.current]);

    const onSlidingStart = () => {
      setSliderBeingDragged(true);
    };
    
    const onSlidingComplete = async (value) => {
      setSliderBeingDragged(false);
      setSliderValue(value);
      const newPosition = value * videoDuration;
      await videoRef.current.setPositionAsync(newPosition);
    };
    
    

    // Function to handle slider value change
    const onSliderValueChange = (value) => {
      setSliderValue(value);
    };
    


    const togglePlayPause = async () => {
        if (videoRef.current) {
          if (isPlaying) {
            await videoRef.current.pauseAsync();
          } else {
            await videoRef.current.playAsync();
          }
          setIsPlaying(!isPlaying);
        }
      };
      useEffect(() => {
        const handleDoubleTap = async () => {
          if (doubleTapRight) {
            // Move video 5 seconds ahead
            const newPosition = Math.min(videoDuration, await videoRef.current.getStatusAsync().then((status) => {
              const { positionMillis } = status;
              return (positionMillis / 1000) + 5; // Convert to seconds
              
            }));
            console.log("New position to the right:",newPosition)
            await videoRef.current.setPositionAsync(newPosition);
            console.log('Position set successfully.',newPosition); 
            await videoRef.current.playAsync(); 
            console.log('Video playback started.'); 
          } else if (doubleTapLeft) {
            // Move video 5 seconds behind
            const newPosition = Math.max(0, await videoRef.current.getStatusAsync().then((status) => {
              const { positionMillis } = status;
              return (positionMillis / 1000) - 5; // Convert to seconds
            }));
            console.log("New position to the left:",newPosition)
            await videoRef.current.setPositionAsync(newPosition);
            console.log('Position set successfully.',newPosition); 
            await videoRef.current.playAsync(); 
            console.log('Video playback started.'); 
          }
        };
    
        handleDoubleTap();
      }, [doubleTapRight, doubleTapLeft]);


    useEffect(() => {
        fetchComments();
      }, [postID]);

      const formatTimestamp = (timestamp) => {
        const currentDate = new Date();
        const postDate = new Date(timestamp);
    
        const timeDifference = currentDate - postDate;
        const secondsDifference = Math.floor(timeDifference / 1000);
        const minutesDifference = Math.floor(secondsDifference / 60);
        const hoursDifference = Math.floor(minutesDifference / 60);
        const daysDifference = Math.floor(hoursDifference / 24);
    
        if (secondsDifference < 60) {
          return `${secondsDifference}s ago`;
        } else if (minutesDifference < 60) {
          return `${minutesDifference}m ago`;
        } else if (hoursDifference < 24) {
          return `${hoursDifference}h ago`;
        } else {
          return `${daysDifference}d ago`;
        }
      };

    const fetchComments = async () => {
        try {
          const { data: commentsData, error: commentsError } = await supabase
            .from('comments')
            .select('*')
            .eq('post_id', postID); 

          if (commentsError) {
            console.error('Error fetching comments:', commentsError);
            return;
          }
    
          // Fetch user details for each comment
        const commentsWithUserDetails = await Promise.all(
          commentsData.map(async (comment) => {
            const { data: userData, error: userError } = await supabase
              .from('profiles')
              .select('*')
              .eq('id', comment.user_id)
              .single();
    
            if (userError) {
              console.error(`Error fetching user details for comment ${comment.comment_id}:`, userError);
              return comment;
            }
    
            return {
              ...comment,
              userDetails: userData || {},
            };
          })
        );
              setComments(commentsWithUserDetails || []);
        } catch (error) {
          console.error('Error in fetchComments function:', error);
        } 
      };

      const renderItem = ({ item: comment }) => (
        <View style={{borderTopWidth:1, borderTopColor:'#B3B3B3'}}>
          <View style={styles.commentcontainer}>
            <View style={styles.profileanduser}>
              <View style={styles.postprofilepicturecontainer}>
                <Image style={styles.postprofilepicture} source={{ uri: comment.userDetails?.profile_picture_url }} />
              </View>
              <Text style={styles.usernameposttext}>@{comment.userDetails?.username}</Text>
              <Text style={styles.timetext}>{formatTimestamp(comment.created_at)}</Text>
            </View>
            <View style={styles.commentviewtextcontainer}>
              <Text style={styles.commentsviewtext}>{comment.text}</Text>
              <View style={styles.commentreactioncontainer}>
              <CommentThumbsUp postId={comment.comment_id} initialLikes={comment.likes} />
              <Text style={styles.userpostreactionstext}>{comment.likes}</Text>
              <CommentThumbsDown postID={comment.comment_id} initialDislikes={comment.dislikes} />
              <Text style={styles.userpostreactionstext}>{comment.dislikes}</Text>
              </View>
            </View>
          </View>
        </View>
    
      );
    

  return (
    <View >
     <StatusBar backgroundColor={'transparent'}/>
    { mediaType === 'image' ?
       
      <ImageBackground style={{width:screenWidth,height:SCREEN_HEIGHT}} source={{uri:media}}>
      <View style={styles.bottomTab}>
        <ThumbsUpIcon postID={postID} initialLikes={initialLikes} />
        <ThumbsDownIcon postID={postID} initialDislikes={initialDislikes} />
        <EchoIcon postID={postID} initialEchoes={initialEchoes}/>
      </View>
      </ImageBackground>
:
    <View>
        <View  style={styles.mediacontainer}>
        <Video
        ref={videoRef}
        style={styles.media}
        source={{uri:media}}
        useNativeControls={false}
        resizeMode={ResizeMode.COVER}
        onPlaybackStatusUpdate={(status) => {
            setIsPlaying(status.isPlaying);
          }}
        isLooping={true}
        />
       </View>
       <View style={styles.controls}>
            <TouchableOpacity onPress={togglePlayPause} style={styles.controlButton}>
                {isPlaying?
                <FontAwesome5 name="pause" size={30} color="white" />
                :
                <FontAwesome5 name="play" size={30} color="white" />
                }
            </TouchableOpacity>
      </View>
      <View style={styles.sliderContainer}>
          <Slider
            style={{ width: 300, height: 40 }}s
            minimumValue={0}
            maximumValue={1}
            value={sliderValue}
            onValueChange={onSliderValueChange}
            onSlidingStart={onSlidingStart}
            onSlidingComplete={onSlidingComplete}
            minimumTrackTintColor="#784EF8"
            maximumTrackTintColor="white"
            thumbTintColor="#784EF8"
          />

      </View>
      <TapGestureHandler
            onHandlerStateChange={({ nativeEvent }) => {
              if (nativeEvent.state === State.ACTIVE) {
                setDoubleTapRight(true);
                setTimeout(() => {
                  setDoubleTapRight(false);
                }, 300); // Adjust timeout as needed
              }
            }}
            numberOfTaps={2}
            maxDelayMs={300}
          >
            <View style={styles.rightDoubleTapArea}></View>
          </TapGestureHandler>
          <TapGestureHandler
            onHandlerStateChange={({ nativeEvent }) => {
              if (nativeEvent.state === State.ACTIVE) {
                setDoubleTapLeft(true);
                setTimeout(() => {
                  setDoubleTapLeft(false);
                }, 300); // Adjust timeout as needed
              }
            }}
            numberOfTaps={2}
            maxDelayMs={300}
          >
            <View style={styles.leftDoubleTapArea}></View>
          </TapGestureHandler>
      
        <View >
        
        <FlatList
        data={Comments}
        keyExtractor={(comment) => comment.comment_id.toString()}
            renderItem={renderItem}
        />
        </View>
    </View>
       }
    </View>

  )
}
0

There are 0 best solutions below