import { useRouter } from 'expo-router';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Pressable, Text, View, type LayoutChangeEvent } from 'react-native';
import { MusicShareSheet } from '../features/social/Social';
import { ListeningBanner } from '../features/social/Listening';
import { trackShareUrl } from '@pipu/core';
import { useSessionCtx, useUser } from '../lib/session';
import { player } from '../player/controller';
import { usePlayerState } from '../player/hooks';
import { useColors } from '../theme';
import { DownloadButton } from '../ui/downloads';
import { Cover, Icon, Screen, formatDuration } from '../ui/kit';
import { WaveOrb } from '../ui/wave/WaveOrb';
/**
* Полноэкранный плеер: вид `cover` (крупная обложка) или `wave` (визуализация волны в цветах обложки) — по профилю;
* прогресс с перемоткой, лайк / дизлайк, скачать, управление.
*/
export default function PlayerScreen() {
const colors = useColors();
const { t } = useTranslation();
const router = useRouter();
const st = usePlayerState();
const locked = st.listening?.locked === true;
const prefs = useUser().ui_prefs;
const { server } = useSessionCtx();
const [sharing, setSharing] = useState(false);
const [barWidth, setBarWidth] = useState(1);
const track = st.track;
if (!track) {
return (
router.back()} style={{ padding: 16 }} accessibilityRole="button" accessibilityLabel={t('mobile.close_player')}>
);
}
const duration = st.durationMs || track.duration_ms;
const progress = duration ? Math.min(st.positionMs / duration, 1) : 0;
const react = (r: 'like' | 'dislike') => void player.react(track, track.reaction === r ? null : r).catch(() => undefined);
const share = () => setSharing(true);
return (
{sharing && server && setSharing(false)} />}
router.back()} hitSlop={10} accessibilityRole="button" accessibilityLabel={t('mobile.close_player')}>
{st.wave ? t('wave.title') : t('mobile.now_playing')}
void share()} disabled={!server || sharing} hitSlop={10} accessibilityRole="button" accessibilityLabel={t('player.share')} accessibilityState={{ disabled: !server || sharing }}>
{prefs.mobile_player === 'wave' ? (
) : (
)}
{track.title}
{track.artists.map((a) => a.name).join(', ')}
router.push({ pathname: '/playlists', params: { track: track.id } })}
accessibilityRole="button" accessibilityLabel={t('playlists.add')}
style={{ flexDirection: 'row', alignItems: 'center', gap: 8, minHeight: 44, alignSelf: 'flex-start' }}>
{t('playlists.add')}
setBarWidth(e.nativeEvent.layout.width || 1)}
disabled={locked} onPress={(e) => player.seek((e.nativeEvent.locationX / barWidth) * duration)}
accessibilityRole="adjustable"
accessibilityLabel={t('player.progress')}
accessibilityValue={{ min: 0, max: Math.round(duration / 1000), now: Math.round(st.positionMs / 1000) }}
accessibilityActions={[{ name: 'increment' }, { name: 'decrement' }]}
onAccessibilityAction={(e) => player.seek(st.positionMs + (e.nativeEvent.actionName === 'increment' ? 10_000 : -10_000))}
style={{ height: 24, justifyContent: 'center' }}
>
{formatDuration(st.positionMs)}
{formatDuration(duration)}
react('dislike')} hitSlop={10} accessibilityRole="button" accessibilityLabel={t(track.reaction === 'dislike' ? 'player.undislike' : 'player.dislike')}>
void player.prev()} hitSlop={10} accessibilityRole="button" accessibilityLabel={t('player.prev')}>
player.toggle()}
accessibilityRole="button"
accessibilityLabel={t(st.playing ? 'player.pause' : 'player.play')}
style={{ width: 72, height: 72, borderRadius: 36, backgroundColor: colors.text, alignItems: 'center', justifyContent: 'center' }}
>
player.next()} hitSlop={10} accessibilityRole="button" accessibilityLabel={t('player.next')}>
react('like')} hitSlop={10} accessibilityRole="button" accessibilityLabel={t(track.reaction === 'like' ? 'player.unlike' : 'player.like')}>
);
}