Files
Toolbox/apps/app_zen_box/screens/PlayerScreen.tsx
T

169 lines
4.2 KiB
TypeScript

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,
},
});