using MudBlazor; namespace PlaylistShared.Pwa.Services; public class AudioPlayerService : IAudioPlayerService { private readonly TokenStorage _tokenStorage; private readonly ISnackbar _snackbar; private string? _currentTrackId; private bool _isPlaying; private double _currentVolume = 70; private double _currentProgress; private string _currentTime = "0:00"; private string _totalTime = "0:00"; public string? CurrentTrackId => _currentTrackId; public bool IsPlaying => _isPlaying; public double CurrentVolume { get => _currentVolume; set { _currentVolume = value; OnStateChanged?.Invoke(); } } public double CurrentProgress => _currentProgress; public string CurrentTime => _currentTime; public string TotalTime => _totalTime; public event Action? OnStateChanged; public AudioPlayerService(TokenStorage tokenStorage, ISnackbar snackbar) { _tokenStorage = tokenStorage; _snackbar = snackbar; } // Внешние команды (вызываются из компонентов) public async Task LoadAndPlayAsync(string trackId, string? accessToken = null, string? sharedPlaylistId = null) { // Если accessToken не передан, пытаемся получить его из хранилища if (string.IsNullOrWhiteSpace(accessToken)) { var tokens = await _tokenStorage.GetTokensAsync(); accessToken = tokens.token; } // Проверяем, есть ли чем авторизоваться if (string.IsNullOrWhiteSpace(accessToken) && string.IsNullOrWhiteSpace(sharedPlaylistId)) { _snackbar.Add("Не удалось воспроизвести трек: отсутствует токен авторизации или идентификатор расшаренного плейлиста.", Severity.Error); return; } _currentTrackId = trackId; _isPlaying = true; OnStateChanged?.Invoke(); OnLoadAndPlayRequested?.Invoke(trackId, accessToken, sharedPlaylistId); } public async Task PlayAsync() { _isPlaying = true; OnStateChanged?.Invoke(); OnPlayRequested?.Invoke(); } public async Task PauseAsync() { _isPlaying = false; OnStateChanged?.Invoke(); OnPauseRequested?.Invoke(); } public async Task StopAsync() { _isPlaying = false; _currentTrackId = null; _currentProgress = 0; _currentTime = "0:00"; OnStateChanged?.Invoke(); OnStopRequested?.Invoke(); } public async Task SeekToAsync(double percent) { OnSeekRequested?.Invoke(percent); } public async Task SetVolumeAsync(double volume) { _currentVolume = volume; OnStateChanged?.Invoke(); OnVolumeChangeRequested?.Invoke(volume); } // События для связи с реальным AudioPlayer компонентом public event Func? OnLoadAndPlayRequested; public event Func? OnPlayRequested; public event Func? OnPauseRequested; public event Func? OnStopRequested; public event Func? OnSeekRequested; public event Func? OnVolumeChangeRequested; // Внутренние методы для обновления состояния из AudioPlayer public void SetPlayingState(bool isPlaying) { _isPlaying = isPlaying; OnStateChanged?.Invoke(); } public void SetCurrentTrack(string? trackId) { _currentTrackId = trackId; OnStateChanged?.Invoke(); } public void UpdateProgress(double progress, string currentTime, string totalTime) { _currentProgress = progress; _currentTime = currentTime; _totalTime = totalTime; OnStateChanged?.Invoke(); } public void NotifyTrackEnded() { _isPlaying = false; _currentTrackId = null; _currentProgress = 0; _currentTime = "0:00"; OnStateChanged?.Invoke(); } }