Reputation: 119
I'm working on a music app using react native track player for playing a song, my current code works with multiple songs, and I would like to know how can we implement one song playing. for example, on a screen, we have a list of all the songs when we click on a specific song we can play that song, and we can go back and choose another song and play that one. I have tried to implement but every time I go back to the song list and choose another song the old one will be playing.
here is my code for multiple songs
import Slider from '@react-native-community/slider';
import React, {useEffect, useRef, useState} from 'react';
import {
Animated,
Dimensions,
Image,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import TrackPlayer, {
State,
usePlaybackState,
useProgress,
} from 'react-native-track-player';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {songType} from '../../../../App';
import Songs from '../DummyData/songs';
interface renderSongTYpe {
item: songType;
}
const {width, height} = Dimensions.get('window');
const setupPlayer = async () => {
console.log('load');
await TrackPlayer.setupPlayer();
await TrackPlayer.add(Songs);
};
const tooglePlayback = async (playbackState: State) => {
const curentTrack = await TrackPlayer.getCurrentTrack();
console.log('cur', curentTrack);
if (curentTrack !== null) {
if (playbackState === State.Playing) {
await TrackPlayer.pause();
} else {
await TrackPlayer.play();
}
}
};
export const MusicPlayer = () => {
const playbackState = usePlaybackState() as State;
const progress = useProgress();
const scrollX = useRef(new Animated.Value(0)).current;
const [songIndex, setSongIndex] = useState(0);
console.log('current state', progress.position);
const songSlider = useRef<any>(null);
const skipTo = async (trackId: number) => {
await TrackPlayer.skip(trackId);
};
useEffect(() => {
setupPlayer();
scrollX.addListener(({value}) => {
// console.log('scroll x', value);
const index = Math.round(value / width);
skipTo(index);
setSongIndex(index);
if (!songSlider.current) {
return;
}
});
return () => {
scrollX.removeAllListeners();
};
}, []);
const skipToNext = () => {
songSlider.current.scrollToOffset({
offset: (songIndex + 1) * width,
});
};
const skipToPrevious = () => {
songSlider.current.scrollToOffset({
offset: (songIndex - 1) * width,
});
};
const renderSongs = ({item}: renderSongTYpe) => {
return (
<Animated.View
style={{width, justifyContent: 'center', alignItems: 'center'}}>
{State.Playing ? (
<View style={styles.artworkwrapper}>
<Image source={item.img} style={styles.artworkimg} />
</View>
) : (
<Text>loading</Text>
)}
</Animated.View>
);
};
function millisToMinutesAndSeconds(millis: number) {
const minutes = Math.floor(millis / 60000);
const seconds = ((millis % 60000) / 1000).toFixed(0) as unknown as number;
return `${minutes < 10 ? '0' : ''}${minutes}:${
seconds < 10 ? '0' : ''
}${seconds}`;
}
return (
<SafeAreaView style={styles.container}>
<View style={styles.mainContainer}>
<View style={{width}}>
<Animated.FlatList
ref={songSlider}
data={Songs}
renderItem={renderSongs}
keyExtractor={item => item.id}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: {x: scrollX},
},
},
],
{useNativeDriver: true},
)}
/>
</View>
<View>
<Text style={styles.title}> {Songs[songIndex].title}</Text>
<Text style={styles.artist}> song artiste</Text>
</View>
<View>
<Slider
thumbTintColor="#ffd369"
minimumTrackTintColor="#ffd369"
maximumTrackTintColor="#fff"
style={styles.progressContainer}
value={progress.position}
minimumValue={0}
maximumValue={progress.duration}
onSlidingComplete={async value => {
await TrackPlayer.seekTo(value);
}}
/>
<View style={styles.progressLabelContainer}>
<Text style={styles.progressLabeltxt}>
{millisToMinutesAndSeconds(progress.position * 1000)}
</Text>
<Text style={styles.progressLabeltxt}>
{millisToMinutesAndSeconds(
(progress.duration - progress.position) * 1000,
)}
</Text>
</View>
</View>
<View style={styles.musicControl}>
<TouchableOpacity onPress={skipToPrevious}>
<Ionicons
name="play-skip-back-outline"
size={35}
color="#ffd369"
style={{marginTop: 15}}
/>
</TouchableOpacity>
<TouchableOpacity onPress={() => tooglePlayback(playbackState)}>
<Ionicons
name={
playbackState === State.Playing
? 'ios-pause'
: 'ios-play-circle'
}
size={75}
color="#ffd369"
/>
</TouchableOpacity>
<TouchableOpacity onPress={skipToNext}>
<Ionicons
name="play-skip-forward-outline"
size={35}
color="#ffd369"
style={{marginTop: 15}}
/>
</TouchableOpacity>
</View>
</View>
<View style={styles.bottomContainer}>
<View style={styles.bottomControls}>
<TouchableOpacity onPress={() => {}}>
<Ionicons name="heart-outline" size={32} color="#777777" />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}}>
<Ionicons name="repeat" size={32} color="#777777" />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}}>
<Ionicons name="share-outline" size={32} color="#777777" />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}}>
<Ionicons name="ellipsis-horizontal" size={32} color="#777777" />
</TouchableOpacity>
</View>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#222831',
},
mainContainer: {
flex: 1,
backgroundColor: '#222831',
alignItems: 'center',
justifyContent: 'center',
},
artworkwrapper: {
width: 300,
height: 340,
marginBottom: 25,
shadowColor: '#ccc',
shadowOffset: {
width: 5,
height: 5,
},
shadowOpacity: 0.5,
shadowRadius: 3.84,
elevation: 5,
},
artworkimg: {
width: '100%',
height: '100%',
borderRadius: 15,
},
title: {
fontSize: 18,
fontWeight: '600',
textAlign: 'center',
color: '#eeeeee',
},
artist: {
fontSize: 16,
fontWeight: '200',
textAlign: 'center',
color: '#eeeeee',
},
progressContainer: {
width: 350,
height: 40,
marginTop: 25,
flexDirection: 'row',
},
progressLabelContainer: {
width: 340,
flexDirection: 'row',
justifyContent: 'space-between',
},
progressLabeltxt: {
color: '#fff',
},
musicControl: {
flexDirection: 'row',
width: '60%',
justifyContent: 'space-between',
},
bottomContainer: {
borderTopColor: '#393E46',
borderTopWidth: 1,
width,
alignItems: 'center',
paddingVertical: 15,
},
bottomControls: {
flexDirection: 'row',
justifyContent: 'space-between',
width: '80%',
},
});
Upvotes: 2
Views: 1654
Reputation: 85
Have the songs seprated each in its own object then pass it to TrackPlayer.add like this
var songObj = {
id: 1,
url: "https://sample.com/song_01.mp3",
title: "Song 01"
}
await TrackPlayer.add([songObj])
this way you play only one track at a time by pressing at it
Upvotes: 2