Добавлена подсветка воспроизводимой песни

This commit is contained in:
FrigaT
2026-05-22 00:07:26 +03:00
parent 9139d8ecfe
commit efe1c3c2dd
23 changed files with 362 additions and 57 deletions

View File

@@ -14,7 +14,7 @@
Paper="true">
<MudPaper Class="pa-4">
<MudText Typo="Typo.body2" Class="mb-2">Ссылка для приглашения:</MudText>
<MudStack Row Gap="2" AlignItems="AlignItems.Center">
<MudStack Row Spacing="2" AlignItems="AlignItems.Center">
<MudTextField @bind-Value="_shareUrl"
ReadOnly="true"
Variant="Variant.Outlined"

View File

@@ -6,18 +6,17 @@
<MudItem @onmouseenter="HandleMouseEnter"
@onmouseleave="HandleMouseLeave"
style="position: relative; display: inline-block; cursor: pointer; border-radius: 4px; overflow: hidden;">
<MudImage Src="@Track?.CoverUri.FormatCoverUrl(Width, Height)" Height="@Height" Width="@Width" Class="rounded" Style="display: block;" />
@if (CanPlay && (_isHovered || IsCurrentTrackPlaying))
@if (CanPlay)
{
<MudItem class="play-overlay"
style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; border-radius: 4px; transition: opacity 0.2s ease; cursor: pointer;">
<MudIconButton Icon="@(IsCurrentTrackPlaying? Icons.Material.Filled.Pause : Icons.Material.Filled.PlayArrow)"
<div class="play-overlay @(_isHovered || IsCurrentTrackPlaying ? "play-overlay--visible" : "")">
<MudIconButton Icon="@(IsCurrentTrackPlaying ? Icons.Material.Filled.Pause : Icons.Material.Filled.PlayArrow)"
Color="Color.Inherit"
Size="Size.Large"
OnClick="OnPlayClick" />
</MudItem>
</div>
}
</MudItem>

View File

@@ -3,7 +3,7 @@
@using PlaylistShared.Pwa.Extensions
@using PlaylistShared.Shared.Yandex
<MudStack Row AlignItems="AlignItems.Center">
<MudStack Row AlignItems="AlignItems.Center" Class="@(IsCurrentTrack ? "current-track" : "")">
<!-- Обложка с фиксированной шириной -->
<MudItem>
<TrackCoverWithPlay TrackId="@Track.TrackId"
@@ -31,13 +31,26 @@
<!-- Длительность (фиксированная ширина по содержимому) -->
<MudItem>
<MudText Typo="Typo.body2">@Track.DurationMs.FormatDuration()</MudText>
@if (IsCurrentTrack)
{
<MudIcon Icon="@Icons.Material.Filled.GraphicEq" Color="Color.Primary" Size="Size.Small" Class="mr-1 eq-animate" Style="vertical-align: middle;" />
}
<MudText Typo="Typo.body2" Inline Color="@(IsCurrentTrack ? Color.Primary : Color.Default)">@Track.DurationMs.FormatDuration()</MudText>
</MudItem>
</MudStack>
<style>
.current-track {
background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
border-radius: 6px;
box-shadow: inset 2px 0 0 var(--mud-palette-primary);
}
</style>
@code {
[Parameter] public YandexTrack Track { get; set; } = null!;
[Parameter] public string PlaylistShareToken { get; set; } = string.Empty;
[Parameter] public bool CanPlay { get; set; } = true;
[Parameter] public string? AddedByName { get; set; }
[Parameter] public bool IsCurrentTrack { get; set; }
}

View File

@@ -9,7 +9,7 @@
@implements IDisposable
@implements IAsyncDisposable
<MudStack Spacing="1" Row AlignItems="AlignItems.Center" Wrap="Wrap.NoWrap">
<MudStack Spacing="1" Row AlignItems="AlignItems.Center" Wrap="Wrap.NoWrap" Class="player-enter">
<!-- Кнопки управления -->
<MudIconButton Icon="@Icons.Material.Filled.SkipPrevious"
Size="Size.Small"
@@ -17,9 +17,7 @@
Disabled="@(!AudioPlayerService.HasPrevious)"
OnClick="() => AudioPlayerService.PlayPreviousAsync()" />
<MudItem @onmouseenter="() => { _isPlayHovered = true; }"
@onmouseleave="() => { _isPlayHovered = false; }"
Class="relative d-inline-block rounded overflow-hidden cursor-pointer"
<MudItem Class="relative d-inline-block rounded overflow-hidden cursor-pointer"
Style="width: 50px; height: 50px;">
@if (!string.IsNullOrEmpty(AudioPlayerService.CurrentTrack?.CoverUri))
@@ -125,7 +123,6 @@
private double _volumeBeforeMute;
private double _bufferSecond;
private bool _isPlayHovered;
protected override async Task OnInitializedAsync()
{
@@ -179,6 +176,29 @@
{
_bufferSecond = second;
}
[JSInvokable]
public async Task OnKeyboardTogglePlay()
{
if (AudioPlayerService.IsPlaying)
await AudioPlayerService.PauseAsync();
else
await AudioPlayerService.PlayAsync();
}
[JSInvokable]
public async Task OnKeyboardSeek(double delta)
{
var newTime = Math.Max(0, AudioPlayerService.CurrentTime + delta);
await AudioPlayerService.SeekToAsync(newTime);
}
[JSInvokable]
public async Task OnKeyboardVolumeChange(double delta)
{
var newVol = Math.Clamp(AudioPlayerService.CurrentVolume + delta, 0, 100);
await AudioPlayerService.SetVolumeAsync(newVol);
}
#endregion
#region Обработка сервиса
@@ -307,7 +327,10 @@
AudioPlayerService.OnStateChanged -= OnServiceStateChanged;
if (_audioElement != null)
{
try { await _audioElement.InvokeVoidAsync("destroy"); } catch { }
await _audioElement.DisposeAsync();
}
if (_audioModule != null)
await _audioModule.DisposeAsync();
}