feat: 初始提交(仅核心代码,已排除大文件)
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import React from 'react';
|
||||
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import Svg, { Path } from 'react-native-svg';
|
||||
import { Starfield } from '../components/Starfield';
|
||||
import { ZenCenter } from '../components/ZenCenter';
|
||||
import { MarqueeText } from '../components/MarqueeText';
|
||||
import { PlayerControls } from '../components/PlayerControls';
|
||||
import { theme } from '../theme';
|
||||
import { Track, RepeatMode } from '../types';
|
||||
|
||||
interface PlayerScreenProps {
|
||||
currentTrack: Track | null;
|
||||
trackCount: number;
|
||||
isPlaying: boolean;
|
||||
isShuffle: boolean;
|
||||
repeatMode: RepeatMode;
|
||||
position: number;
|
||||
duration: number;
|
||||
onPlayPause: () => void;
|
||||
onNext: () => void;
|
||||
onPrev: () => void;
|
||||
onShuffle: () => void;
|
||||
onRepeat: () => void;
|
||||
onSeek: (position: number) => void;
|
||||
onOpenPlaylist: () => void;
|
||||
}
|
||||
|
||||
const ListIcon = () => (
|
||||
<Svg width={24} height={24} viewBox="0 0 24 24" fill="none" stroke={theme.colors.textSecondary} strokeWidth={2} strokeLinecap="round">
|
||||
<Path d="M8 6h13M8 12h13M8 18h13" />
|
||||
<Path d="M3 6h.01M3 12h.01M3 18h.01" />
|
||||
</Svg>
|
||||
);
|
||||
|
||||
export const PlayerScreen: React.FC<PlayerScreenProps> = ({
|
||||
currentTrack,
|
||||
trackCount,
|
||||
isPlaying,
|
||||
isShuffle,
|
||||
repeatMode,
|
||||
position,
|
||||
duration,
|
||||
onPlayPause,
|
||||
onNext,
|
||||
onPrev,
|
||||
onShuffle,
|
||||
onRepeat,
|
||||
onSeek,
|
||||
onOpenPlaylist,
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* Starfield background */}
|
||||
<Starfield />
|
||||
|
||||
<SafeAreaView style={styles.safeContainer} edges={['top', 'bottom']}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.headerTitle}>观空禅音</Text>
|
||||
<Text style={styles.headerCount}>{trackCount} 首</Text>
|
||||
</View>
|
||||
|
||||
{/* Zen center */}
|
||||
<View style={styles.zenCenterContainer}>
|
||||
<ZenCenter isPlaying={isPlaying} />
|
||||
</View>
|
||||
|
||||
{/* Track info */}
|
||||
<View style={styles.trackInfo}>
|
||||
<MarqueeText
|
||||
text={currentTrack?.title || '未选择歌曲'}
|
||||
enabled={!!currentTrack?.title}
|
||||
style={styles.trackTitle}
|
||||
containerStyle={styles.trackTitleWrap}
|
||||
/>
|
||||
<Text style={styles.trackArtist} numberOfLines={1}>
|
||||
{currentTrack?.artist || '—'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Spacer */}
|
||||
<View style={styles.spacer} />
|
||||
|
||||
{/* Player controls */}
|
||||
<PlayerControls
|
||||
isPlaying={isPlaying}
|
||||
isShuffle={isShuffle}
|
||||
repeatMode={repeatMode}
|
||||
position={position}
|
||||
duration={duration}
|
||||
onPlayPause={onPlayPause}
|
||||
onNext={onNext}
|
||||
onPrev={onPrev}
|
||||
onShuffle={onShuffle}
|
||||
onRepeat={onRepeat}
|
||||
onSeek={onSeek}
|
||||
/>
|
||||
|
||||
{/* Playlist button */}
|
||||
<View style={styles.playlistButtonContainer}>
|
||||
<TouchableOpacity style={styles.playlistButton} onPress={onOpenPlaylist}>
|
||||
<ListIcon />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
safeContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: theme.spacing.md,
|
||||
paddingVertical: theme.spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
letterSpacing: 0.06,
|
||||
color: theme.colors.text,
|
||||
},
|
||||
headerCount: {
|
||||
fontSize: 13,
|
||||
color: theme.colors.textSecondary,
|
||||
},
|
||||
zenCenterContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
trackInfo: {
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: theme.spacing.md,
|
||||
},
|
||||
trackTitleWrap: {
|
||||
width: '100%',
|
||||
},
|
||||
trackTitle: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: theme.colors.text,
|
||||
marginBottom: 3,
|
||||
},
|
||||
trackArtist: {
|
||||
fontSize: 13,
|
||||
color: theme.colors.textSecondary,
|
||||
},
|
||||
spacer: {
|
||||
height: theme.spacing.md,
|
||||
},
|
||||
playlistButtonContainer: {
|
||||
alignItems: 'center',
|
||||
paddingBottom: theme.spacing.sm,
|
||||
},
|
||||
playlistButton: {
|
||||
padding: theme.spacing.sm,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user