Добавлены избранные плейлисты

This commit is contained in:
FrigaT
2026-04-14 14:14:19 +03:00
parent 8230951839
commit dcb2efbedb
17 changed files with 1118 additions and 5 deletions

View File

@@ -2,8 +2,9 @@
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Главная</MudNavLink>
<AuthorizeView>
<Authorized>
<MudNavLink Href="/my-playlists" Icon="@Icons.Material.Filled.QueueMusic">Мои плейлисты</MudNavLink>
<MudNavLink Href="/profile" Icon="@Icons.Material.Filled.Person">Профиль</MudNavLink>
<MudNavLink Href="/my-playlists" Icon="@Icons.Material.Filled.QueueMusic">Мои плейлисты</MudNavLink>
<MudNavLink Href="/favorites" Icon="@Icons.Material.Filled.Favorite">Избранное</MudNavLink>
</Authorized>
</AuthorizeView>
</MudNavMenu>

View File

@@ -0,0 +1,112 @@
@page "/favorites"
@attribute [Authorize]
@using PlaylistShared.Shared.DTO
@inject HttpClient Http
@inject ISnackbar Snackbar
@inject NavigationManager Navigation
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8">
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h5">Избранные плейлисты</MudText>
<MudText Typo="Typo.body2">Расшаренные плейлисты, которые вы добавили в избранное</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="LoadFavorites" />
</CardHeaderActions>
</MudCardHeader>
<MudCardContent>
@if (_loading)
{
<MudProgressCircular Indeterminate />
}
else if (_favorites == null || !_favorites.Any())
{
<MudAlert Severity="Severity.Info">
У вас пока нет избранных плейлистов. Перейдите на страницу расшаренного плейлиста и нажмите ★, чтобы добавить.
</MudAlert>
}
else
{
<MudTable Items="@_favorites">
<HeaderContent>
<MudTh>Название</MudTh>
<MudTh>Владелец</MudTh>
<MudTh>Треков</MudTh>
<MudTh></MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Название">
<MudLink Href="@($"/shared/{context.ShareToken}")" Underline="Underline.Hover">
@context.Title
</MudLink>
</MudTd>
<MudTd DataLabel="Владелец">@context.Creator?.UserName</MudTd>
<MudTd DataLabel="Треков">@context.TrackCount</MudTd>
<MudTd DataLabel="">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Color="Color.Error"
OnClick="() => RemoveFromFavorites(context)"
Title="Удалить из избранного" />
</MudTd>
</RowTemplate>
</MudTable>
}
</MudCardContent>
</MudCard>
</MudContainer>
@code {
private List<SharedPlaylistDto> _favorites = new();
private bool _loading = true;
protected override async Task OnInitializedAsync()
{
await LoadFavorites();
}
private async Task LoadFavorites()
{
_loading = true;
try
{
var response = await Http.GetFromJsonAsync<ApiResponse<List<SharedPlaylistDto>>>("/api/favorites");
if (response?.Success == true)
_favorites = response.Data ?? new();
else
Snackbar.Add(response?.Error?.Message ?? "Ошибка загрузки избранного", Severity.Error);
}
catch (Exception ex)
{
Snackbar.Add($"Ошибка: {ex.Message}", Severity.Error);
}
finally
{
_loading = false;
StateHasChanged();
}
}
private async Task RemoveFromFavorites(SharedPlaylistDto playlist)
{
try
{
var response = await Http.DeleteAsync($"/api/favorites/{playlist.ShareToken}");
if (response.IsSuccessStatusCode)
{
Snackbar.Add($"Плейлист \"{playlist.Title}\" удалён из избранного", Severity.Success);
await LoadFavorites();
}
else
{
var error = await response.Content.ReadFromJsonAsync<ApiResponse<object>>();
Snackbar.Add(error?.Error?.Message ?? "Ошибка удаления", Severity.Error);
}
}
catch (Exception ex)
{
Snackbar.Add($"Ошибка: {ex.Message}", Severity.Error);
}
}
}

View File

@@ -27,10 +27,21 @@
<div style="display: flex; gap: 16px; align-items: center;">
@if (!string.IsNullOrEmpty(_playlist.CoverUrl))
{
<MudImage Src="@FormatCoverUrl(_playlist.CoverUrl)" Height="80" Width="80" Class="rounded" />
<MudImage Src="@FormatCoverUrl(_playlist.CoverUrl, "80x80")" Height="80" Width="80" Class="rounded" />
}
<div>
<MudText Typo="Typo.h5">@_playlist.Title</MudText>
<div style="display: flex; align-items: center; gap: 8px;">
<MudLink Href="@($"https://music.yandex.ru/playlists/{_playlist.YandexPlaylistUuid}")" Target="_blank" Underline="Underline.Hover">
@_playlist.Title
<MudIcon Icon="@Icons.Material.Filled.OpenInNew" Size="Size.Small" Class="ml-1" />
</MudLink>
<MudIconButton Icon="@(_isFavorite? Icons.Material.Filled.Favorite : Icons.Material.Outlined.FavoriteBorder)"
Color="Color.Error"
OnClick="ToggleFavorite"
Disabled="_favoriteLoading"
Size="Size.Medium" />
</div>
<MudText Typo="Typo.body2" Color="Color.Secondary">Владелец: @_playlist.Creator?.UserName</MudText>
</div>
</div>
@@ -212,6 +223,9 @@
private bool _savingPermissions;
private string? _currentUserId;
private bool _isFavorite = false;
private bool _favoriteLoading = false;
private List<YandexTrackDisplay> _tracks = new();
private bool _tracksLoading;
@@ -226,6 +240,67 @@
await LoadPlaylist();
}
private async Task CheckFavoriteStatus()
{
if (!_isAuthenticated || _playlist == null) return;
try
{
var response = await Http.GetFromJsonAsync<ApiResponse<bool>>($"/api/favorites/{Token}/check");
if (response?.Success == true)
_isFavorite = response.Data;
}
catch { }
}
private async Task ToggleFavorite()
{
if (!_isAuthenticated)
{
Snackbar.Add("Добавление в избранное доступно только авторизованным пользователям", Severity.Warning);
return;
}
_favoriteLoading = true;
try
{
if (_isFavorite)
{
var response = await Http.DeleteAsync($"/api/favorites/{Token}");
if (response.IsSuccessStatusCode)
{
_isFavorite = false;
Snackbar.Add("Плейлист удалён из избранного", Severity.Success);
}
else
{
Snackbar.Add("Ошибка удаления из избранного", Severity.Error);
}
}
else
{
var response = await Http.PostAsync($"/api/favorites/{Token}", null);
if (response.IsSuccessStatusCode)
{
_isFavorite = true;
Snackbar.Add("Плейлист добавлен в избранное", Severity.Success);
}
else
{
Snackbar.Add("Ошибка добавления в избранное", Severity.Error);
}
}
}
catch (Exception ex)
{
Snackbar.Add($"Ошибка: {ex.Message}", Severity.Error);
}
finally
{
_favoriteLoading = false;
StateHasChanged();
}
}
private async Task ConfigurePermissions()
{
if (_playlist is null)
@@ -275,8 +350,8 @@
_playlist = response.Data;
await ConfigurePermissions();
await LoadTracks();
await CheckFavoriteStatus();
}
else
{