React Native Expo AV - Implementing SeekBar

Viewed 1189

I am attempting to use react-native-slider with Expo AV to create a seekbar, but am having trouble updating the 'value' state of slider. When I try to set it to currentPosition/durationPosition, it errors out, likely because initially these values are NaN. I CAN display current/duration however.

My best guess is that I need a way to wait until my mp3 is loaded before rendering the SeekBar. I probably also need to do a better job of separating components and keep PlayerScreen very minimal. I've messed around with this code so much I can barely remember what I've tried... Getting close to ditching Expo because react-native-track-player looks easier to work with and I've heard some bad things about Expo. Anyways, here's where I'm at now

export default class PlayerScreen extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
    isPlaying: false,
    playbackObject: null,
    volume: 1.0,
    isBuffering: false,
    paused: true,
    currentIndex: 0,
    durationMillis: 1,
    positionMillis:0,
    sliderValue:0,
    isSeeking:false,
    }
  }

  async componentDidMount() {
    try {
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: false,
        interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
        playsInSilentModeIOS: true,
        interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,
        shouldDuckAndroid: true,
        staysActiveInBackground: true,
        playThroughEarpieceAndroid: true
      })
      this.loadAudio()
    } catch (e) {
      console.log(e)
    }
  }

  async loadAudio() {
    const { currentIndex, isPlaying, volume} = this.state

    try {
      const playbackObject = new Audio.Sound()
      const source = {
        uri: this.props.route.params.item.uri
      }

      const status = {
        shouldPlay: isPlaying,
        volume,
      }

      playbackObject.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate)
      await playbackObject.loadAsync(source, status, true)
      this.setState({playbackObject})
      var sliderValue = this.state.positionMillis/this.state.durationMillis
      } catch (e) {
        console.log(e)
      }
  }

  handlePlayPause = async () => {
    const { isPlaying, playbackObject } = this.state
    isPlaying ? await playbackObject.pauseAsync() : await playbackObject.playAsync()
    this.setState({
      isPlaying: !isPlaying
    })
  }

  onPlaybackStatusUpdate = status => {
    this.setState({
      isBuffering: status.isBuffering,
      durationMillis: status.durationMillis,
      positionMillis: status.positionMillis,
    })
  }

  render() {
    const { item } = this.props.route.params;
    return (
      <View style={globalStyles.container}>
        <Header />
        <View style={globalStyles.subHeader}>
          <Text style={globalStyles.title}>{ item.title }</Text>
        </View>
        <View style={styles.text}>
          <Text>{ item.text }</Text>
        </View>
        <SeekBar
        durationMillis={this.state.durationMillis}
        positionMillis={this.state.positionMillis}
        sliderValue={this.state.sliderValue}
        />

And here's the SeekBar component:

  const SeekBar = ({
    positionMillis,
    durationMillis,
    sliderValue
  }) => {

    return (
      <View style={styles.container}>
        <View style={{ flexDirection: 'row' }}>
          <View style={{ flex: 1 }} />
          <Text style={[styles.text, { width: 40 }]}>
            {positionMillis + ' / ' + durationMillis}
          </Text>
        </View>
        <Slider

          minimumValue={0}
          maximumValue={1}
          value={sliderValue}
          style={styles.slider}
          minimumTrackTintColor='#fff'
          maximumTrackTintColor='rgba(255, 255, 255, 0.14)'
          />
      </View>
    );
  };

  export default SeekBar;
1 Answers

put

<SeekBar
        durationMillis={this.state.durationMillis}
        positionMillis={this.state.positionMillis}
        sliderValue={this.state.sliderValue}
        />

in the screen component and

const SeekBar = ({
  positionMillis,
  durationMillis,
  sliderValue
}) => {
  sliderValue = positionMillis/durationMillis
  return (
    <View style={styles.container}>
      <View style={{ flexDirection: 'row' }}>
        <View style={{ flex: 1 }} />

in the SeekBar component

Related