diff --git a/src/screens/Player/components/ProgressBar.tsx b/src/screens/Player/components/ProgressBar.tsx index c8591c6..19d6710 100644 --- a/src/screens/Player/components/ProgressBar.tsx +++ b/src/screens/Player/components/ProgressBar.tsx @@ -1,8 +1,11 @@ -import React from 'react'; -import { useTrackPlayerProgress } from 'react-native-track-player'; +import React, { Component } from 'react'; +import TrackPlayer, { State as PlayerState } from 'react-native-track-player'; import styled from 'styled-components/native'; -import { View, Text } from 'react-native'; -import { padStart } from 'lodash'; +import { View, Text, Dimensions } from 'react-native'; +import { padStart, debounce } from 'lodash'; +import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; + +const Screen = Dimensions.get('screen'); const Container = styled.View` width: 100%; @@ -24,7 +27,7 @@ const PositionIndicator = styled.View<{ progress: number }>` border-radius: 100px; border: 1px solid #eee; background-color: white; - transform: translateX(-10px) translateY(-8.5px); + transform: translateX(${props => props.translation ? props.translation - 20 : -10}px) translateY(-8.5px); position: absolute; top: 0; left: ${props => props.progress * 100}%; @@ -46,20 +49,100 @@ function getMinutes(seconds: number): number { return Math.floor(seconds / 60); } -export default function ProgressBar() { - const { position, duration } = useTrackPlayerProgress(500); +interface State { + position: number; + duration: number; + gesture?: { + previousState?: PlayerState; + translation?: number; + } +} - return ( - <> - - - - - - 0:00 - {getMinutes(position)}:{getSeconds(position)} - {getMinutes(duration)}:{getSeconds(duration)} - - - ); +export default class ProgressBar extends Component<{}, State> { + state: State = { + position: 0, + duration: 0, + } + + timer: number = 0; + + componentDidMount() { + this.timer = setInterval(this.updateProgress, 500); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + updateProgress = async () => { + const [position, duration] = await Promise.all([ + TrackPlayer.getPosition(), + TrackPlayer.getDuration(), + ]); + + this.setState({ position, duration }); + } + + handleGesture = async (event: PanGestureHandlerGestureEvent) => { + // Check if the gesture has started, and if it has not, prepare the player + if (!this.state.gesture) { + // Pause the player and store the previous state + TrackPlayer.getState() + .then((previousState) => this.setState({ gesture: { previousState }})) + .then(() => TrackPlayer.pause()); + + } + + // Set relative translation in state + this.setState({ + gesture: { + previousState: this.state.gesture?.previousState, + translation: event.nativeEvent?.absoluteX, + }, + }); + + // Trigger the end of gesture function + this.handleEndOfGesture(); + } + + handleEndOfGesture = debounce(() => { + // Calculate and set the new position + const { gesture, duration } = this.state; + const progress = Math.min(Math.max((gesture?.translation || 0) / Screen.width, 0), 1); + const position = Math.floor(duration * progress); + TrackPlayer.seekTo(position); + + // Restart the player + if (this.state.gesture?.previousState === TrackPlayer.STATE_PLAYING) { + TrackPlayer.play(); + } + + this.setState({ gesture: undefined, position }); + }, 500); + + render() { + const { position, duration, gesture } = this.state; + const progress = gesture + ? Math.min(Math.max((gesture?.translation || 0) / Screen.width, 0), 1) + : position / duration; + + return ( + <> + + + + + + + + 0:00 + {gesture + ? {getMinutes(duration * progress)}:{getSeconds(duration * progress)} + : {getMinutes(position)}:{getSeconds(position)} + } + {getMinutes(duration)}:{getSeconds(duration)} + + + ); + } } \ No newline at end of file