diff --git a/PlaylistShared.Pwa/Components/Common/ShareDialog.razor b/PlaylistShared.Pwa/Components/Common/ShareDialog.razor new file mode 100644 index 0000000..6e82422 --- /dev/null +++ b/PlaylistShared.Pwa/Components/Common/ShareDialog.razor @@ -0,0 +1,45 @@ +@inject IJSRuntime JS +@inject ISnackbar Snackbar + + + + Поделиться плейлистом + + + + Скопируйте ссылку и отправьте её друзьям: + + + + + + Скопировать ссылку + + + Закрыть + + + + +@code { + [CascadingParameter] + private IMudDialogInstance MudDialog { get; set; } = default!; + + [Parameter] + public string ShareUrl { get; set; } = string.Empty; + + private async Task CopyToClipboard() + { + await JS.InvokeVoidAsync("navigator.clipboard.writeText", ShareUrl); + Snackbar.Add("Ссылка скопирована в буфер обмена!", Severity.Success); + MudDialog.Close(DialogResult.Ok(true)); + } + + private void Close() => MudDialog.Cancel(); +} \ No newline at end of file diff --git a/PlaylistShared.Pwa/Pages/SharedPlaylistView.razor b/PlaylistShared.Pwa/Pages/SharedPlaylistView.razor index 426e7df..169c4e4 100644 --- a/PlaylistShared.Pwa/Pages/SharedPlaylistView.razor +++ b/PlaylistShared.Pwa/Pages/SharedPlaylistView.razor @@ -16,6 +16,8 @@ @inject AuthenticationStateProvider AuthProvider @inject IDialogService DialogService @inject IAudioPlayerService AudioPlayerService +@inject IJSRuntime JS +@inject IDialogService DialogService @implements IDisposable @@ -32,18 +34,23 @@ @PlaylistCardHeaderContent + + + @if (_isCreator && _isAuthenticated) { } - + @@ -116,7 +123,10 @@ OnClick="ToggleFavorite" Disabled="@_favoriteLoading" /> - + + @if (_isCreator && _isAuthenticated) { Загрузка признака "фаворит". private bool _favoriteLoading; + + /******************************** + * Поделиться ссылкой + *********************************/ + private IJSObjectReference? _shareModule; + private bool _isWebShareSupported = false; protected override async Task OnInitializedAsync() { @@ -417,6 +433,18 @@ AudioPlayerService.OnEndedTrack += OnPlayerStateChanged; } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + // Загружаем JS-модуль + _shareModule = await JS.InvokeAsync("import", "/js/shareUtils.js"); + // Проверяем поддержку Web Share API + _isWebShareSupported = await _shareModule.InvokeAsync("isSupported"); + StateHasChanged(); + } + } + private void OnPlayerStateChanged() { InvokeAsync(StateHasChanged); @@ -803,9 +831,58 @@ } #endregion + #region Поделитьсы ссылкой + /// Поделиться ссылкой + private async Task SharePlaylist() + { + if (_shareModule == null) return; + + var shareUrl = Navigation.Uri; + var shareTitle = "🎵 Поделиться плейлистом"; + var shareText = _playlist?.Title != null + ? $"Послушайте плейлист '{_playlist.Title}'!" + : "Послушайте этот плейлист!"; + + if (_isWebShareSupported) + { + var result = await _shareModule.InvokeAsync("shareLink", shareTitle, shareText, shareUrl); + if (result?.Success == false && !string.IsNullOrEmpty(result.Error) && !result.Cancelled) + { + Snackbar.Add($"Не удалось поделиться: {result.Error}", Severity.Warning); + await ShowShareDialog(shareUrl); + } + } + else + { + await ShowShareDialog(shareUrl); + } + } + + /// Модальное окно, чтобы поделиться ссылкой + private async Task ShowShareDialog(string url) + { + var parameters = new DialogParameters + { + { x => x.ShareUrl, url } + }; + var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.Small, FullWidth = true }; + await DialogService.ShowAsync("Поделиться", parameters, options); + } + + // Вспомогательный класс для результата + private class ShareResult + { + public bool Success { get; set; } + public string? Error { get; set; } + public bool Cancelled { get; set; } + } + #endregion + public void Dispose() { AudioPlayerService.OnStartedTrack -= OnPlayerStateChanged; AudioPlayerService.OnEndedTrack -= OnPlayerStateChanged; + + _shareModule?.DisposeAsync(); } } \ No newline at end of file diff --git a/PlaylistShared.Pwa/PlaylistShared.Pwa.csproj b/PlaylistShared.Pwa/PlaylistShared.Pwa.csproj index 4fb904a..d600199 100644 --- a/PlaylistShared.Pwa/PlaylistShared.Pwa.csproj +++ b/PlaylistShared.Pwa/PlaylistShared.Pwa.csproj @@ -28,6 +28,9 @@ Always + + Always + diff --git a/PlaylistShared.Pwa/wwwroot/js/shareUtils.js b/PlaylistShared.Pwa/wwwroot/js/shareUtils.js new file mode 100644 index 0000000..b99272d --- /dev/null +++ b/PlaylistShared.Pwa/wwwroot/js/shareUtils.js @@ -0,0 +1,19 @@ +export function isSupported() { + return !!navigator.share; +} + +export async function shareLink(title, text, url) { + if (!navigator.share) { + return { success: false, error: 'Web Share API не поддерживается' }; + } + try { + await navigator.share({ title, text, url }); + return { success: true }; + } catch (error) { + if (error.name === 'AbortError') { + return { success: false, cancelled: true }; + } + console.error('Ошибка при шеринге:', error); + return { success: false, error: error.message }; + } +} \ No newline at end of file