Skip to content

Commit

Permalink
feat:打开播放列表跳转到当前播放歌曲
Browse files Browse the repository at this point in the history
  • Loading branch information
gyc-12 committed Aug 18, 2024
1 parent 47bf1a7 commit 70eb954
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 98 deletions.
68 changes: 31 additions & 37 deletions src/app/(modals)/playList.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,38 @@
import React, { useEffect, useState } from 'react';
import { colors, screenPadding } from '@/constants/tokens';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StyleSheet, View,Text } from 'react-native';
import { defaultStyles } from '@/styles';
import { useHeaderHeight } from '@react-navigation/elements';
import { Track, useActiveTrack } from 'react-native-track-player';
import myTrackPlayer from '@/helpers/trackPlayerIndex';
import { usePlayerBackground } from '@/hooks/usePlayerBackground';
import { unknownTrackImageUri } from '@/constants/images';
import { NowPlayList } from '@/components/NowPlayList';
import { NowPlayList } from '@/components/NowPlayList'
import { colors, screenPadding } from '@/constants/tokens'
import { usePlayList } from '@/store/playList'
import { defaultStyles } from '@/styles'
import { useHeaderHeight } from '@react-navigation/elements'
import React from 'react'
import { StyleSheet } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { Track } from 'react-native-track-player'

const PlayListScreen = () => {
const headerHeight = useHeaderHeight();
const tracks = usePlayList();
const headerHeight = useHeaderHeight()
const tracks = usePlayList()


return (

<SafeAreaView style={[styles.modalContainer, { paddingTop: headerHeight }]}>
<Text style={styles.header}>播放列表</Text>
<NowPlayList id='PlayListScreen' tracks={tracks as Track[]} />
</SafeAreaView>
);
};
return (
<SafeAreaView style={[styles.modalContainer, { paddingTop: headerHeight }]}>
<NowPlayList id="PlayListScreen" tracks={tracks as Track[]} />
</SafeAreaView>
)
}

const styles = StyleSheet.create({
modalContainer: {
flex: 1,
paddingHorizontal: screenPadding.horizontal,
backgroundColor: defaultStyles.container.backgroundColor, // 设置默认背景颜色
},
header: {
fontSize: 28,
fontWeight: 'bold',
padding: 0,
paddingBottom: 20,
paddingTop: 0,
color: colors.text,
},
});
modalContainer: {
flex: 1,
paddingHorizontal: screenPadding.horizontal,
backgroundColor: defaultStyles.container.backgroundColor, // 设置默认背景颜色
},
header: {
fontSize: 28,
fontWeight: 'bold',
padding: 0,
paddingBottom: 20,
paddingTop: 0,
color: colors.text,
},
})

export default PlayListScreen;
export default PlayListScreen
216 changes: 155 additions & 61 deletions src/components/NowPlayList.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { TracksListItem } from '@/components/TracksListItem'
import { unknownTrackImageUri } from '@/constants/images'

import { colors } from '@/constants/tokens'
import myTrackPlayer from '@/helpers/trackPlayerIndex'
import { utilsStyles } from '@/styles'
import React, { useRef } from 'react'
import { FlatList, FlatListProps, Text, View } from 'react-native'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { FlatList, FlatListProps, StyleSheet, Text, View } from 'react-native'
import FastImage from 'react-native-fast-image'
import TrackPlayer, { Track, useActiveTrack } from 'react-native-track-player'

import myTrackPlayer, { qualityStore } from '@/helpers/trackPlayerIndex'
import { myGetMusicUrl } from '@/helpers/userApi/getMusicSource'
import { useSafeAreaInsets } from 'react-native-safe-area-context'



import { Track, useActiveTrack } from 'react-native-track-player'

export type TracksListProps = Partial<FlatListProps<Track>> & {
//以及所有来自 FlatListProps 的属性,且这些属性都是可选的。
id: string
tracks: Track[]
hideQueueControls?: boolean
Expand All @@ -24,68 +18,168 @@ export type TracksListProps = Partial<FlatListProps<Track>> & {
const ItemDivider = () => (
<View style={{ ...utilsStyles.itemSeparator, marginVertical: 9, marginLeft: 60 }} />
)

const ITEM_HEIGHT = 60 // 假设每个项目的高度为60,根据实际情况调整

export const NowPlayList = ({
id,
tracks,
hideQueueControls = false,
...flatlistProps
}: TracksListProps) => {
const flatListRef = useRef<FlatList<Track>>(null)
const activeTrack = useActiveTrack()
const [initialIndex, setInitialIndex] = useState<number | null>(null)
const { top } = useSafeAreaInsets()
const getItemLayout = useCallback(
(data: any, index: number) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
}),
[],
)

const handleTrackSelect = async (selectedTrack: Track) => {
useEffect(() => {
if (activeTrack) {
const index = tracks.findIndex((track) => track.id === activeTrack.id)
if (index !== -1) {
setInitialIndex(index)
}
}
}, [activeTrack, tracks])

// if(selectedTrack.url=='Unknown'||selectedTrack.url.includes('fake')) {
// const res = await myGetMusicUrl(selectedTrack, qualityStore.getValue())
// selectedTrack.url = res.url
// }
await myTrackPlayer.play(selectedTrack as IMusic.IMusicItem)
}
const DismissPlayerSymbol = () => {
const { top } = useSafeAreaInsets();
const handleTrackSelect = useCallback(async (selectedTrack: Track) => {
await myTrackPlayer.play(selectedTrack as IMusic.IMusicItem)
}, [])

return (
<View
style={{
position: 'absolute',
top: top-18,
left: 0,
right: 0,
flexDirection: 'row',
justifyContent: 'center',
}}
>
<View
accessible={false}
style={{
width: 50,
height: 8,
borderRadius: 8,
backgroundColor: '#fff',
opacity: 0.7,
}}
/>
</View>
);
};
return (
<><DismissPlayerSymbol />
<FlatList
data={tracks}
contentContainerStyle={{ paddingTop: 10, paddingBottom: 128 }}
ListFooterComponent={ItemDivider}
ItemSeparatorComponent={ItemDivider}
const handleScrollToIndexFailed = useCallback(
(info: { index: number; highestMeasuredFrameIndex: number; averageItemLength: number }) => {
const wait = new Promise((resolve) => setTimeout(resolve, 100))
wait.then(() => {
flatListRef.current?.scrollToIndex({
index: info.index,
animated: false,
viewPosition: 0.5,
})
})
},
[],
)

const DismissPlayerSymbol = useCallback(() => {
return (
<View
style={{
position: 'absolute',
top: top - 28,
left: 0,
right: 0,
flexDirection: 'row',
justifyContent: 'center',
}}
>
<View
accessible={false}
style={{
width: 50,
height: 8,
borderRadius: 8,
backgroundColor: '#fff',
opacity: 0.7,
}}
/>
</View>
)
}, [])

const renderItem = useCallback(
({ item: track }: { item: Track }) => (
<TracksListItem track={track} onTrackSelect={handleTrackSelect} />
),
[handleTrackSelect],
)

ListEmptyComponent={<View>
const keyExtractor = useCallback((item: Track) => item.id, [])

<Text style={utilsStyles.emptyContentText}>No songs </Text>
const initialNumToRender = useMemo(() => {
if (initialIndex !== null) {
return Math.max(20, initialIndex + 10) // 确保至少渲染20个项目或当前项目上方10个项目
}
return 20
}, [initialIndex])

<FastImage
source={{ uri: unknownTrackImageUri, priority: FastImage.priority.normal }}
style={utilsStyles.emptyContentImage} />
</View>}
renderItem={({ item: track }) => (
<TracksListItem track={track} onTrackSelect={handleTrackSelect} /> //将 track 和 handleTrackSelect 作为 props 传递给它。
return (
<>
<DismissPlayerSymbol />
<Text style={styles.header}>播放列表</Text>
{initialIndex == null ? (
<></>
) : (
<FlatList
data={tracks}
contentContainerStyle={{ paddingTop: 10, paddingBottom: 128 }}
ListFooterComponent={ItemDivider}
ItemSeparatorComponent={ItemDivider}
ref={flatListRef}
getItemLayout={getItemLayout}
initialScrollIndex={initialIndex}
ListEmptyComponent={
<View>
<Text style={utilsStyles.emptyContentText}>No songs </Text>
<FastImage
source={{ uri: unknownTrackImageUri, priority: FastImage.priority.normal }}
style={utilsStyles.emptyContentImage}
/>
</View>
}
onScrollToIndexFailed={handleScrollToIndexFailed}
renderItem={renderItem}
keyExtractor={keyExtractor}
initialNumToRender={initialNumToRender}
maxToRenderPerBatch={10}
windowSize={21}
removeClippedSubviews={false}
updateCellsBatchingPeriod={50}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
autoscrollToTopThreshold: 10,
}}
{...flatlistProps}
/>
)}
{...flatlistProps} /></>
</>
)

}

const styles = StyleSheet.create({
headerContainer: {
paddingTop: 20,
paddingBottom: 10,
},
lineContainer: {
position: 'absolute',
top: -20,
left: 0,
right: 0,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: 10,
},
line: {
width: 50,
height: 8,
borderRadius: 8,
backgroundColor: '#fff',
opacity: 0.7,
},
header: {
fontSize: 28,
fontWeight: 'bold',
padding: 0,
paddingBottom: 20,
marginTop: -5,
color: colors.text,
},
})

0 comments on commit 70eb954

Please sign in to comment.