Skip to content

Commit

Permalink
Add: Flatlist to lyric
Browse files Browse the repository at this point in the history
  • Loading branch information
sawyerf committed Dec 27, 2024
1 parent 32763bd commit b670e4f
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 78 deletions.
81 changes: 6 additions & 75 deletions app/components/player/FullScreenPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { ConfigContext } from '~/contexts/config';
import { SongContext } from '~/contexts/song';
import { ThemeContext } from '~/contexts/theme';
import { nextSong, previousSong, pauseSong, resumeSong, secondToTime, setRepeat, updateTime } from '~/utils/player';
import { parseLrc } from '~/utils/lrc';
import { setPosition } from '~/utils/player';
import { urlCover, getApi } from '~/utils/api';
import FavoritedButton from '~/components/button/FavoritedButton';
import IconButton from '~/components/button/IconButton';
import SlideBar from '~/components/button/SlideBar';
import SongsList from '~/components/lists/SongsList';
import mainStyles from '~/styles/main';
import Lyric from '~/components/player/Lyric';

const preview = {
COVER: 0,
Expand All @@ -23,61 +23,15 @@ const preview = {

const FullScreenPlayer = ({ fullscreen }) => {
const [isPreview, setIsPreview] = React.useState(preview.COVER)
const [lyrics, setLyrics] = React.useState([])
const [song, songDispatch] = React.useContext(SongContext)
const config = React.useContext(ConfigContext)
const insets = useSafeAreaInsets();
const theme = React.useContext(ThemeContext)
const time = updateTime()

React.useEffect(() => {
setIsPreview(preview.COVER)
setLyrics([])
}, [song.songInfo])

const getNavidromeLyrics = () => {
getApi(config, 'getLyricsBySongId', { id: song.songInfo.id })
.then(res => {
const ly = res.lyricsList?.structuredLyrics[0]?.line?.map(ly => ({ time: ly.start / 1000, text: ly.value.length ? ly.value : '...' }))
if (ly.length == 0) { // not found
return getLrcLibLyrics()
}
ly.sort((a, b) => a.time - b.time)
setLyrics(ly)
setIsPreview(preview.LYRICS)
})
.catch(() => { // not found
getLrcLibLyrics()
})
}

const getLrcLibLyrics = () => {
const params = {
track_name: song.songInfo.title,
artist_name: song.songInfo.artist,
album_name: song.songInfo.album,
duration: song.songInfo.duration
}
fetch('https://lrclib.net/api/get?' + Object.keys(params).map((key) => `${key}=${encodeURIComponent(params[key])}`).join('&'), {
headers: { 'Lrclib-Client': 'Castafiore' }
})
.then(res => res.json())
.then(res => {
const ly = parseLrc(res.syncedLyrics)
setLyrics(ly)
setIsPreview(preview.LYRICS)
})
.catch(() => {
setIsPreview(preview.LYRICS)
setLyrics([{ time: 0, text: 'No lyrics found' }])
})
}

const getLyrics = async () => {
if (isPreview == preview.LYRICS) return setIsPreview(preview.COVER)
if (lyrics.length > 0) return setIsPreview(preview.LYRICS)
getNavidromeLyrics()
}
React.useEffect(() => {
setIsPreview(preview.COVER)
}, [song.songInfo])

return (
<Modal
Expand Down Expand Up @@ -114,30 +68,7 @@ const FullScreenPlayer = ({ fullscreen }) => {
</ScrollView>
}
{
isPreview == preview.LYRICS &&
<ScrollView style={{ ...styles.albumImage(), borderRadius: null }} showsVerticalScrollIndicator={false}>
{lyrics.map((lyric, index) => {
if (index < lyrics.length - 2 && time.position >= lyrics[index + 2]?.time) return null
const isCurrent = time.position >= lyric.time && (lyrics.length == index + 1 || time.position < lyrics[index + 1]?.time)
return (
<View key={index} style={{
display: 'flex',
justifyContent: 'flex-end',
minHeight: ((time.position > lyric.time && !isCurrent) || !index) ? 62 : 0,
}}>
<Text
key={index}
style={{
color: isCurrent ? theme.primaryLight : theme.secondaryLight,
fontSize: 23,
textAlign: 'center',
}}>
{lyric.text.length ? lyric.text : '...'}
</Text>
</View>
)
})}
</ScrollView>
isPreview == preview.LYRICS && <Lyric song={song} time={time} style={styles.albumImage()} />
}
<View style={{ flexDirection: 'row', marginTop: 20, width: '100%' }}>
<View style={{ flex: 1 }}>
Expand Down Expand Up @@ -197,7 +128,7 @@ const FullScreenPlayer = ({ fullscreen }) => {
size={19}
color={isPreview == preview.LYRICS ? theme.primaryTouch : theme.secondaryLight}
style={{ paddingVertical: 10 }}
onPress={() => getLyrics()}
onPress={() => setIsPreview(isPreview == preview.LYRICS ? preview.COVER : preview.LYRICS)}
/>
<IconButton
icon="bars"
Expand Down
111 changes: 111 additions & 0 deletions app/components/player/Lyric.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React from 'react'
import { View, Text, ScrollView, FlatList, Pressable } from 'react-native'

import { ThemeContext } from '~/contexts/theme'
import { getApi } from '~/utils/api'
import { parseLrc } from '~/utils/lrc'
import { setPosition } from '~/utils/player'
import AsyncStorage from '@react-native-async-storage/async-storage'


const Lyric = ({ song, time, style }) => {
const theme = React.useContext(ThemeContext)
const [lyrics, setLyrics] = React.useState([])
const refScroll = React.useRef(null)
const [indexCurrent, setIndex] = React.useState(0)

React.useEffect(() => {
getLyrics()
}, [song.songInfo])

const getLyrics = () => {
AsyncStorage.getItem(`lyrics/${song.songInfo.id}`)
.then(res => {
if (res) {
const ly = JSON.parse(res)
setLyrics(ly)
} else {
getNavidromeLyrics()
}
})
}

React.useEffect(() => {
if (lyrics.length == 0) return
const index = lyrics.findIndex(ly => ly.time > time.position) - 1
if (index < 0) return
if (index !== indexCurrent) {
refScroll.current.scrollToIndex({ index, animated: true, viewOffset: 0, viewPosition: 0.5 })
setIndex(index)
}
}, [time.position])

const getNavidromeLyrics = () => {
getApi(config, 'getLyricsBySongId', { id: song.songInfo.id })
.then(res => {
const ly = res.lyricsList?.structuredLyrics[0]?.line?.map(ly => ({ time: ly.start / 1000, text: ly.value.length ? ly.value : '...' }))
if (ly.length == 0) { // not found
return getLrcLibLyrics()
}
ly.sort((a, b) => a.time - b.time)
setLyrics(ly)
AsyncStorage.setItem(`lyrics/${song.songInfo.id}`, JSON.stringify(ly))
})
.catch(() => { // not found
getLrcLibLyrics()
})
}

const getLrcLibLyrics = () => {
const params = {
track_name: song.songInfo.title,
artist_name: song.songInfo.artist,
album_name: song.songInfo.album,
duration: song.songInfo.duration
}
fetch('https://lrclib.net/api/get?' + Object.keys(params).map((key) => `${key}=${encodeURIComponent(params[key])}`).join('&'), {
headers: { 'Lrclib-Client': 'Castafiore' }
})
.then(res => res.json())
.then(res => {
const ly = parseLrc(res.syncedLyrics)
setLyrics(ly)
AsyncStorage.setItem(`lyrics/${song.songInfo.id}`, JSON.stringify(ly))
})
.catch(() => {
setLyrics([{ time: 0, text: 'No lyrics found' }])
})
}

return (
<FlatList
style={{ ...style, borderRadius: null }}
showsVerticalScrollIndicator={false}
data={lyrics}
ref={refScroll}
initialNumToRender={lyrics.length}
onScrollToIndexFailed={(error) => { console.log(error) }}
keyExtractor={(item, index) => index}
renderItem={({ item, index }) => {
return (
<Pressable
onPress={() => {
setPosition(item.time)
}}
>
<Text
style={{
color: index === indexCurrent ? theme.primaryLight : theme.secondaryLight,
fontSize: 23,
textAlign: 'center',
}}>
{item.text.length ? item.text : '...'}
</Text>
</Pressable>
)
}}
/>
)
}

export default Lyric
8 changes: 5 additions & 3 deletions app/screens/Settings/Cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,6 @@ const CacheSettings = () => {
</View>
<Text style={settingStyles.titleContainer(theme)}>Cache Stats</Text >
<View style={settingStyles.optionsContainer(theme)}>
{statCache.length === 0 && <View style={settingStyles.optionItem(theme, true)}>
<Text style={{ color: theme.primaryLight, fontSize: 16, fontWeight: '400' }}>No Cache</Text>
</View>}
<FlatList
data={statCache}
renderItem={({ item, index }) => (
Expand All @@ -99,6 +96,11 @@ const CacheSettings = () => {
/>
)}
keyExtractor={(item, index) => index}
ListEmptyComponent={(
<View style={settingStyles.optionItem(theme, true)}>
<Text style={{ color: theme.primaryLight, fontSize: 16, fontWeight: '400' }}>No Cache</Text>
</View>
)}
/>
</View>
</View>
Expand Down

0 comments on commit b670e4f

Please sign in to comment.