import { useNavigation } from '@react-navigation/native' import { useAtomValue } from 'jotai/utils' import React, { useEffect } from 'react' import { StatusBar, StyleSheet, Text, View } from 'react-native' import { NativeStackScreenProps } from 'react-native-screens/lib/typescript/native-stack' import { 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 { currentTrackAtom, playerStateAtom, queueNameAtom, useNext, usePause, usePlay, usePrevious, useProgress, } from '@app/state/trackplayer' import colors from '@app/styles/colors' import font from '@app/styles/font' import formatDuration from '@app/util/formatDuration' import CoverArt from '@app/components/CoverArt' import ImageGradientBackground from '@app/components/ImageGradientBackground' import PressableOpacity from '@app/components/PressableOpacity' import dimensions from '@app/styles/dimensions' const NowPlayingHeader = () => { const queueName = useAtomValue(queueNameAtom) const navigation = useNavigation() return ( navigation.goBack()} style={headerStyles.icons} ripple={true}> {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, }, queueName: { fontFamily: font.bold, fontSize: 16, color: colors.text.primary, flex: 1, textAlign: 'center', }, }) const SongCoverArt = () => { const track = useAtomValue(currentTrackAtom) return ( } height={'100%'} width={'100%'} coverArtUri={track?.artwork as string} /> ) } const coverArtStyles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', paddingBottom: 20, }, }) const SongInfo = () => { const track = useAtomValue(currentTrackAtom) return ( {track?.title} {track?.artist} ) } const infoStyles = StyleSheet.create({ container: { width: '100%', flexDirection: 'row', }, 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 } = useProgress() let progress = 0 if (duration > 0) { progress = position / duration } return ( {formatDuration(position)} {formatDuration(duration)} ) } const seekStyles = StyleSheet.create({ container: { width: '100%', marginTop: 26, }, barContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 6, }, bars: { backgroundColor: colors.text.primary, height: 4, }, 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', }, text: { fontFamily: font.regular, fontSize: 15, color: colors.text.primary, }, }) const PlayerControls = () => { const state = useAtomValue(playerStateAtom) const play = usePlay() const pause = usePause() const next = useNext() const previous = usePrevious() let playPauseIcon: string let playPauseAction: undefined | (() => void) let disabled: boolean switch (state) { case State.Playing: case State.Buffering: case State.Connecting: disabled = false playPauseIcon = 'pause-circle' playPauseAction = pause break case State.Paused: disabled = false playPauseIcon = 'play-circle' playPauseAction = play break default: disabled = true playPauseIcon = 'play-circle' playPauseAction = undefined break } return ( ) } const controlsStyles = StyleSheet.create({ container: { width: '100%', }, 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', }, }) type RootStackParamList = { Main: undefined NowPlaying: undefined } type NowPlayingProps = NativeStackScreenProps const NowPlayingLayout: React.FC = ({ navigation }) => { const track = useAtomValue(currentTrackAtom) useEffect(() => { if (!track && navigation.canGoBack()) { navigation.popToTop() } }) return ( ) } const styles = StyleSheet.create({ container: { flex: 1, paddingTop: StatusBar.currentHeight, }, content: { flex: 1, paddingHorizontal: 30, }, }) export default NowPlayingLayout