import CoverArt from '@app/components/CoverArt'
import ImageGradientBackground from '@app/components/ImageGradientBackground'
import PressableOpacity from '@app/components/PressableOpacity'
import Star from '@app/components/Star'
import { useStarred } from '@app/hooks/music'
import {
useNext,
usePause,
usePlay,
usePrevious,
useSeekTo,
useToggleRepeat,
useToggleShuffle,
} from '@app/hooks/trackplayer'
import { selectMusic } from '@app/state/music'
import { useStore } from '@app/state/store'
import { QueueContextType, selectTrackPlayer } from '@app/state/trackplayer'
import colors from '@app/styles/colors'
import dimensions from '@app/styles/dimensions'
import font from '@app/styles/font'
import formatDuration from '@app/util/formatDuration'
import { useNavigation } from '@react-navigation/native'
import React, { useCallback, useEffect, useState } from 'react'
import { StatusBar, StyleSheet, Text, View } from 'react-native'
import { NativeStackScreenProps } from 'react-native-screens/native-stack'
import { RepeatMode, State } from 'react-native-track-player'
import IconFA from 'react-native-vector-icons/FontAwesome'
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
import Icon from 'react-native-vector-icons/Ionicons'
import IconMatCom from 'react-native-vector-icons/MaterialCommunityIcons'
import IconMat from 'react-native-vector-icons/MaterialIcons'
import Slider from '@react-native-community/slider'
function getContextName(type?: QueueContextType) {
switch (type) {
case 'album':
return 'Album'
case 'artist':
return 'Top Songs'
case 'playlist':
return 'Playlist'
case 'song':
return 'Search Results'
default:
return undefined
}
}
const NowPlayingHeader = React.memo(() => {
const navigation = useNavigation()
const queueName = useStore(selectTrackPlayer.name)
const queueContextType = useStore(selectTrackPlayer.queueContextType)
const queueContextId = useStore(selectTrackPlayer.queueContextId)
let contextName = getContextName(queueContextType)
const back = useCallback(() => {
navigation.navigate('top')
}, [navigation])
const goToContext = useCallback(() => {
if (!queueContextType || !queueContextId || queueContextType === 'song') {
return
}
navigation.navigate('library')
navigation.navigate(queueContextType, { id: queueContextId, title: queueName })
}, [navigation, queueContextId, queueContextType, queueName])
return (
{contextName ? (
{contextName}
) : (
<>>
)}
{queueName || 'Nothing playing...'}
)
})
const headerStyles = StyleSheet.create({
container: {
height: dimensions.header,
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
icons: {
height: 42,
width: 42,
marginHorizontal: 8,
},
center: {
flex: 1,
},
queueType: {
fontFamily: font.regular,
fontSize: 14,
color: colors.text.primary,
// flex: 1,
textAlign: 'center',
},
queueName: {
fontFamily: font.bold,
fontSize: 16,
color: colors.text.primary,
// flex: 1,
textAlign: 'center',
},
})
const SongCoverArt = () => {
const track = useStore(selectTrackPlayer.currentTrack)
return (
)
}
const coverArtStyles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
paddingBottom: 10,
paddingHorizontal: 10,
},
image: {
height: '100%',
width: '100%',
},
})
const SongInfo = () => {
const track = useStore(selectTrackPlayer.currentTrack)
const id = track?.id || '-1'
const type = 'song'
const starred = useStarred(id, type)
const setStarred = useStore(selectMusic.starItem)
return (
{track?.title}
{track?.artist}
setStarred(id, type, starred)}>
)
}
const infoStyles = StyleSheet.create({
container: {
width: '100%',
flexDirection: 'row',
paddingHorizontal: 10,
},
details: {
flex: 1,
marginRight: 20,
},
controls: {
justifyContent: 'center',
},
title: {
height: 28,
fontFamily: font.bold,
fontSize: 22,
color: colors.text.primary,
},
artist: {
height: 20,
fontFamily: font.regular,
fontSize: 16,
color: colors.text.secondary,
},
})
const SeekBar = () => {
const { position, duration } = useStore(selectTrackPlayer.progress)
const seekTo = useSeekTo()
const [value, setValue] = useState(0)
const [sliding, setSliding] = useState(false)
useEffect(() => {
if (sliding) {
return
}
setValue(position)
}, [position, sliding])
const onSlidingStart = useCallback(() => {
setSliding(true)
}, [])
const onSlidingComplete = useCallback(
async (val: number) => {
await seekTo(val)
setSliding(false)
},
[seekTo],
)
return (
{formatDuration(value)}
{formatDuration(duration)}
)
}
const seekStyles = StyleSheet.create({
container: {
width: '100%',
marginTop: 16,
},
barContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 0,
},
bars: {
backgroundColor: colors.text.primary,
height: 4,
},
slider: {
flex: 1,
height: 40,
},
barLeft: {
marginRight: -6,
},
barRight: {
opacity: 0.3,
marginLeft: -6,
},
indicator: {
height: 12,
width: 12,
borderRadius: 6,
backgroundColor: colors.text.primary,
elevation: 1,
},
textContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 10,
},
text: {
fontFamily: font.regular,
fontSize: 15,
color: colors.text.primary,
},
})
const PlayerControls = () => {
const state = useStore(selectTrackPlayer.playerState)
const play = usePlay()
const pause = usePause()
const next = useNext()
const previous = usePrevious()
const shuffled = useStore(selectTrackPlayer.shuffled)
const toggleShuffle = useToggleShuffle()
const repeatMode = useStore(selectTrackPlayer.repeatMode)
const toggleRepeat = useToggleRepeat()
const navigation = useNavigation()
let playPauseIcon: string
let playPauseAction: undefined | (() => void)
let disabled: boolean
switch (state) {
case State.Playing:
disabled = false
playPauseIcon = 'pause-circle'
playPauseAction = pause
break
default:
disabled = false
playPauseIcon = 'play-circle'
playPauseAction = play
break
}
return (
toggleRepeat()} disabled={disabled}>
1
toggleShuffle()} disabled={disabled}>
navigation.navigate('queue')} disabled={disabled}>
)
}
const controlsStyles = StyleSheet.create({
container: {
width: '100%',
paddingHorizontal: 10,
},
top: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingBottom: 8,
},
bottom: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingTop: 10,
paddingBottom: 54,
},
play: {
marginHorizontal: 30,
},
center: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
repeatExt: {
color: colors.accent,
fontFamily: font.bold,
fontSize: 14,
position: 'absolute',
top: 26,
opacity: 0,
},
})
type RootStackParamList = {
top: undefined
main: undefined
}
type NowPlayingProps = NativeStackScreenProps
const NowPlayingView: React.FC = ({ navigation }) => {
const track = useStore(selectTrackPlayer.currentTrack)
useEffect(() => {
if (!track) {
navigation.navigate('top')
}
})
return (
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: StatusBar.currentHeight,
},
content: {
flex: 1,
paddingHorizontal: 20,
},
})
export default NowPlayingView