You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.6 KiB
185 lines
4.6 KiB
import React, { useState, useEffect } from "react"; |
|
import { StyleSheet, TouchableOpacity, View, Image, Text } from "react-native"; |
|
import { Ionicons } from "@expo/vector-icons"; |
|
import { Audio } from "expo-av"; |
|
|
|
const audioBookPlaylist = [ |
|
{ |
|
title: "Hamlet - Act I", |
|
author: "William Shakespeare", |
|
source: "Librivox", |
|
uri: "", |
|
imageSource: |
|
"http://www.archive.org/download/LibrivoxCdCoverArt8/hamlet_1104.jpg", |
|
}, |
|
|
|
]; |
|
|
|
const MusicPlayer = () => { |
|
const [isPlaying, setIsPlaying] = useState(false); |
|
const [playbackInstance, setPlaybackInstance] = useState(null); |
|
const [currentIndex, setCurrentIndex] = useState(0); |
|
const [volume, setVolume] = useState(1.0); |
|
const [isBuffering, setIsBuffering] = useState(true); |
|
|
|
useEffect( async () => { |
|
try { |
|
await Audio.setAudioModeAsync({ |
|
allowsRecordingIOS: false, |
|
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX, |
|
playsInSilentModeIOS: true, |
|
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX, |
|
shouldDuckAndroid: true, |
|
staysActiveInBackground: true, |
|
playThroughEarpieceAndroid: true, |
|
}); |
|
|
|
loadAudio(); |
|
} catch (e) { |
|
console.log(e); |
|
} |
|
}); |
|
|
|
const loadAudio = async () => { |
|
try { |
|
const playbackInstance = new Audio.Sound(); |
|
const source = { |
|
uri: audioBookPlaylist[currentIndex].uri, |
|
}; |
|
|
|
const status = { |
|
shouldPlay: isPlaying, |
|
volume: volume, |
|
}; |
|
|
|
playbackInstance.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate); |
|
await playbackInstance.loadAsync(source, status, false); |
|
setPlaybackInstance(playbackInstance); |
|
} catch (e) { |
|
console.log(e); |
|
} |
|
}; |
|
|
|
const onPlaybackStatusUpdate = (status) => { |
|
setIsBuffering(status.isBuffering); |
|
}; |
|
|
|
const handlePlayPause = async () => { |
|
if(isPlaying) { |
|
await playbackInstance.pauseAsync(); |
|
}else{ |
|
await playbackInstance.playAsync(); |
|
} |
|
|
|
setIsPlaying(() => !isPlaying); |
|
}; |
|
|
|
const handlePreviousTrack = async () => { |
|
let { playbackInstance, currentIndex } = state; |
|
if (playbackInstance) { |
|
await playbackInstance.unloadAsync(); |
|
setCurrentIndex( |
|
currentIndex === 0 ? audioBookPlaylist.length - 1 : currentIndex - 1 |
|
); |
|
loadAudio(); |
|
} |
|
}; |
|
|
|
const handleNextTrack = async () => { |
|
if (playbackInstance) { |
|
await playbackInstance.unloadAsync(); |
|
setCurrentIndex( |
|
currentIndex + 1 > audioBookPlaylist.length - 1 ? 0 : currentIndex + 1 |
|
); |
|
loadAudio(); |
|
} |
|
}; |
|
|
|
const renderFileInfo = () => { |
|
return playbackInstance ? ( |
|
<View style={styles.trackInfo}> |
|
<Text style={[styles.trackInfoText, styles.largeText]}> |
|
{audioBookPlaylist[currentIndex].title} |
|
</Text> |
|
<Text style={[styles.trackInfoText, styles.smallText]}> |
|
{audioBookPlaylist[currentIndex].author} |
|
</Text> |
|
<Text style={[styles.trackInfoText, styles.smallText]}> |
|
{audioBookPlaylist[currentIndex].source} |
|
</Text> |
|
</View> |
|
) : null; |
|
}; |
|
return ( |
|
<View style={styles.container}> |
|
<Image |
|
style={styles.albumCover} |
|
source={{ |
|
uri: "http://www.archive.org/download/LibrivoxCdCoverArt8/hamlet_1104.jpg", |
|
}} |
|
/> |
|
<View style={styles.controls}> |
|
<TouchableOpacity |
|
style={styles.control} |
|
onPress={() => handlePreviousTrack()} |
|
> |
|
<Ionicons name="play-back" size={48} color="#444" /> |
|
</TouchableOpacity> |
|
<TouchableOpacity |
|
style={styles.control} |
|
onPress={() => handlePlayPause()} |
|
> |
|
{isPlaying ? ( |
|
<Ionicons name="ios-pause" size={48} color="#444" /> |
|
) : ( |
|
<Ionicons name="ios-play-circle" size={48} color="#444" /> |
|
)} |
|
</TouchableOpacity> |
|
<TouchableOpacity |
|
style={styles.control} |
|
onPress={() => handleNextTrack()} |
|
> |
|
<Ionicons name="play-forward" size={48} color="#444" /> |
|
</TouchableOpacity> |
|
</View> |
|
{renderFileInfo()} |
|
</View> |
|
); |
|
}; |
|
|
|
const styles = StyleSheet.create({ |
|
container: { |
|
flex: 1, |
|
backgroundColor: "#fff", |
|
alignItems: "center", |
|
justifyContent: "center", |
|
}, |
|
albumCover: { |
|
width: 250, |
|
height: 250, |
|
}, |
|
trackInfo: { |
|
padding: 40, |
|
backgroundColor: "#fff", |
|
}, |
|
|
|
trackInfoText: { |
|
textAlign: "center", |
|
flexWrap: "wrap", |
|
color: "#550088", |
|
}, |
|
largeText: { |
|
fontSize: 22, |
|
}, |
|
smallText: { |
|
fontSize: 16, |
|
}, |
|
control: { |
|
margin: 20, |
|
}, |
|
controls: { |
|
flexDirection: "row", |
|
}, |
|
}); |
|
|
|
export default MusicPlayer; |