Изменение инструкции получения токена яндекса

This commit is contained in:
FrigaT
2026-04-17 16:48:46 +03:00
parent ab56c34646
commit 6b399f7fb7
4 changed files with 147 additions and 154 deletions

View File

@@ -0,0 +1,93 @@
@using System.Text.RegularExpressions
@using PlaylistShared.Shared.DTO
@inject HttpClient Http
@inject ISnackbar Snackbar
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Подключение Яндекс.Музыки</MudText>
</TitleContent>
<DialogContent>
<MudStepper @bind-ActiveIndex="_index" Vertical CenterLabels CompletedStepColor="Color.Success" @onwheel="HandleWheel">
<ChildContent>
<MudStep Title="Вход" Skippable>
<MudText Typo="Typo.body2" Class="mb-4">Нажмите на кнопку и разрешите доступ приложению.</MudText>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@PlaylistShared.Pwa.CustomIcons.Yandex"
Href="https://oauth.yandex.ru/authorize?response_type=token&client_id=23cabbbdc6cd418abb4b39c32c41195d"
Target="_blank"
@onclick="() => {_index++;}"
FullWidth>
Войти в Яндекс
</MudButton>
</MudStep>
<MudStep Title="Добавление токена">
Скопируйте значение <code>access_token</code> или <code>весь URL</code> из адресной строки после перенаправления.
<MudAlert Severity="Severity.Info" Class="mt-4">
https://music.yandex.ru/#access_token=<code>ВАШ_ТОКЕН</code>&...
</MudAlert>
<MudTextField @bind-Value="_rawInput" @bind-Value:after="Submit" Label="Вставьте скопированную ссылку или токен" Variant="Variant.Outlined" Margin="Margin.Dense" Error="_tokenErr" />
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="Submit" FullWidth Class="mt-4">
Сохранить
</MudButton>
</MudStep>
</ChildContent>
<ActionContent Context="stepper">
<MudIconButton OnClick="@(() => stepper.PreviousStepAsync())" Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Primary" Disabled="@(_index <= 0)" />
<MudSpacer />
<MudIconButton OnClick="@(() => stepper.NextStepAsync())" Icon="@Icons.Material.Filled.ArrowForward" Color="Color.Primary" Disabled="@(_index >= 1)" />
</ActionContent>
</MudStepper>
</DialogContent>
</MudDialog>
@code {
[CascadingParameter] IMudDialogInstance MudDialog { get; set; }
private string _rawInput = "";
private int _index;
private bool _tokenErr = false;
private async Task HandleWheel(WheelEventArgs e)
{
if (e.DeltaY > 0 && _index < 1) // Прокрутка вниз -> Вперед
{
_index++;
}
else if (e.DeltaY < 0 && _index > 0) // Прокрутка вверх -> Назад
{
_index--;
}
}
private async Task Submit()
{
var token = ExtractToken(_rawInput);
if (string.IsNullOrWhiteSpace(token))
{
_tokenErr = true;
Snackbar.Add("Токен не найден", Severity.Error);
return;
}
_tokenErr = false;
var response = await Http.PostAsJsonAsync("/api/yandextoken/set", new SetYandexTokenRequest { Token = token });
if (response.IsSuccessStatusCode)
{
Snackbar.Add("Токен успешно обновлен", Severity.Success);
MudDialog.Close(DialogResult.Ok(true));
}
else
{
Snackbar.Add("Ошибка обновления токена. Повторите позже.", Severity.Error);
}
}
private string ExtractToken(string input) =>
input.Contains("access_token=") ? Regex.Match(input, @"access_token=([^&]+)").Groups[1].Value : input.Trim();
public class SetYandexTokenRequest { public string Token { get; set; } }
}

View File

@@ -1,78 +0,0 @@
@* Компонент с инструкцией по получению токена Яндекс.Музыки *@
<MudContainer Class="pa-4">
<MudText Typo="Typo.body2" GutterBottom>
Токен нужен для доступа к вашим плейлистам. Получите его один раз:
</MudText>
<!-- Вертикальный список шагов -->
<MudStack Class="my-4">
<MudStack Row AlignItems="AlignItems.Center">
<MudPaper Elevation="0" Style="width: 28px; height: 28px; background-color: var(--mud-palette-primary); color: white; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: bold;">1</MudPaper>
<MudText>
Перейдите по <MudLink Href="https://oauth.yandex.ru/authorize?response_type=token&client_id=23cabbbdc6cd418abb4b39c32c41195d" Target="_blank">ссылке</MudLink>
</MudText>
</MudStack>
<MudStack Row AlignItems="AlignItems.Center">
<MudPaper Elevation="0" Style="width: 28px; height: 28px; background-color: var(--mud-palette-primary); color: white; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: bold;">1</MudPaper>
<MudText>
Авторизуйтесь в Яндексе (если ещё не вошли)
</MudText>
</MudStack>
<MudStack Row AlignItems="AlignItems.Center">
<MudPaper Elevation="0" Style="width: 28px; height: 28px; background-color: var(--mud-palette-primary); color: white; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: bold;">1</MudPaper>
<MudText>
Нажмите «Разрешить»
</MudText>
</MudStack>
<MudStack Row AlignItems="AlignItems.Center">
<MudPaper Elevation="0" Style="width: 28px; height: 28px; background-color: var(--mud-palette-primary); color: white; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: bold;">1</MudPaper>
<MudText>
Скопируйте <strong>access_token</strong> из адресной строки после перенаправления
</MudText>
</MudStack>
</MudStack>
<MudAlert Severity="Severity.Info" Class="mt-4">
Пример: <code>https://music.yandex.ru/#access_token=ВАШ_ТОКЕН&...</code>
</MudAlert>
<MudAlert Severity="Severity.Warning" Class="mt-2">
Токен даёт доступ к вашим плейлистам. Никому его не сообщайте.
</MudAlert>
<MudAlert Severity="Severity.Success" Class="mt-2" Icon="@Icons.Material.Filled.Security">
Ваш токен сохраняется в зашифрованном виде и никому не передаётся.
</MudAlert>
</MudContainer>
<style>
.instruction-steps {
margin: 16px 0;
}
.step-item {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.step-number {
width: 28px;
height: 28px;
background-color: var(--mud-palette-primary);
color: white;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: bold;
flex-shrink: 0;
}
.step-content {
flex: 1;
font-size: 0.9rem;
}
</style>

View File

@@ -0,0 +1,8 @@
namespace PlaylistShared.Pwa;
public static class CustomIcons
{
// SVG путь для логотипа Яндекса (буква Я в круге или просто Я)
public const string Yandex = "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm.72 15.79h-2.14v-1.58c-.37.49-.87.89-1.48 1.18-.61.29-1.29.44-2.03.44-1.2 0-2.13-.34-2.8-.1-1.02-.66-1.52-1.61-1.52-2.84 0-1.25.43-2.22 1.28-2.91.85-.69 2.05-1.04 3.59-1.04h1.1v-.84c0-.62-.15-1.07-.46-1.34-.31-.27-.79-.41-1.44-.41-.53 0-1.02.08-1.48.24-.46.16-.9.41-1.32.74v-1.8c.48-.25 1.01-.45 1.58-.59.57-.14 1.15-.21 1.74-.21 1.45 0 2.53.33 3.23 1 .7.67 1.05 1.66 1.05 2.97v6.29zm-2.14-5.18h-.9c-.8 0-1.4.15-1.8.44-.4.29-.6.74-.6 1.34 0 .55.16.96.48 1.23.32.27.76.41 1.32.41.51 0 .97-.13 1.37-.39.4-.26.6-.64.6-1.14v-1.89z";
}

View File

@@ -1,65 +1,52 @@
@page "/profile" @page "/profile"
<PageTitle>Профиль - Playlist Share</PageTitle>
@using Microsoft.AspNetCore.Authorization
@using PlaylistShared.Pwa.Components.Profile
@using PlaylistShared.Shared.DTO
@attribute [Authorize] @attribute [Authorize]
@inject HttpClient Http @inject HttpClient Http
@inject ISnackbar Snackbar @inject IDialogService DialogService
@using PlaylistShared.Pwa.Components.Profile
@using PlaylistShared.Shared.Profile
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-8"> <MudContainer MaxWidth="MaxWidth.Small" Class="mt-8">
<MudCard> <MudText Typo="Typo.h4" Class="mb-6">Профиль</MudText>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h5">Личный кабинет</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudStack Row Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center" Class="mb-4">
<MudText Typo="Typo.body2">
Здесь вы можете указать токен доступа к Яндекс.Музыке.
</MudText>
<MudIconButton Icon="@Icons.Material.Filled.HelpOutline"
Color="Color.Info"
OnClick="() => _instructionDrawerOpen = true"
Title="Как получить токен?" />
</MudStack>
<MudTextField @bind-Value="_token" Label="Токен Яндекс.Музыки" Variant="Variant.Outlined" FullWidth="true" /> <MudStack Spacing="4">
@*
<!-- Секция почты -->
<MudCard>
<MudCardContent>
<MudText Typo="Typo.h6" GutterBottom="true">Данные аккаунта</MudText>
<MudTextField @bind-Value="_email" Label="Электронная почта" ReadOnly="true" Variant="Variant.Outlined" Margin="Margin.Dense" />
<MudButton Variant="Variant.Text" Color="Color.Primary" Class="mt-2" Disabled="true">Сменить почту</MudButton>
</MudCardContent>
</MudCard>
*@
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="SaveToken" Class="mt-4" FullWidth="true"> <!-- Секция Яндекс.Музыки -->
Сохранить токен <MudCard>
</MudButton> <MudCardContent>
<MudStack Row Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Class="mt-4" Typo="Typo.body2">Статус: @_statusText</MudText> <MudStack Spacing="0">
</MudCardContent> <MudText Typo="Typo.h6">Яндекс.Музыка</MudText>
</MudCard> <MudText Typo="Typo.body2" Color="@(_hasToken? Color.Success: Color.Error)">
@_statusText
</MudText>
</MudStack>
<MudButton Variant="Variant.Outlined"
Color="Color.Primary"
OnClick="OpenTokenDialog">
@(_hasToken ? "Переподключить" : "Установить")
</MudButton>
</MudStack>
</MudCardContent>
</MudCard>
</MudStack>
</MudContainer> </MudContainer>
<!-- Выдвижная панель с инструкцией -->
<MudDrawer @bind-Open="_instructionDrawerOpen"
Anchor="Anchor.Right"
Variant="DrawerVariant.Temporary"
Elevation="3"
Width="500px"
MiniWidth="0px">
<MudDrawerHeader>
<MudText Typo="Typo.h6">Как получить токен Яндекс.Музыки</MudText>
</MudDrawerHeader>
<MudDivider />
<YandexTokenInstructions />
</MudDrawer>
@code { @code {
private string _token = ""; private string _email = "user@example.com"; // Загрузите из стейта или API
private string _statusText = "Загрузка..."; private string _statusText = "Загрузка...";
private bool _instructionDrawerOpen = false; private bool _hasToken;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync() => await LoadStatus();
{
await LoadStatus();
}
private async Task LoadStatus() private async Task LoadStatus()
{ {
@@ -68,36 +55,19 @@
var response = await Http.GetFromJsonAsync<ApiResponse<YandexTokenStatus>>("/api/yandextoken/status"); var response = await Http.GetFromJsonAsync<ApiResponse<YandexTokenStatus>>("/api/yandextoken/status");
if (response?.Success == true) if (response?.Success == true)
{ {
_statusText = response.Data.HasToken _hasToken = response.Data.HasToken;
? $"Токен установлен{(response.Data.IsValid ? "" : " (просрочен)")}" _statusText = _hasToken ? "Аккаунт подключен" : "Аккаунт не подключен";
: "Токен не установлен";
} }
} }
catch { _statusText = "Не удалось загрузить статус"; } catch { _statusText = "Ошибка загрузки статуса"; }
} }
private async Task SaveToken() private async Task OpenTokenDialog()
{ {
if (string.IsNullOrWhiteSpace(_token)) var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true };
{ var dialog = await DialogService.ShowAsync<YandexTokenDialog>("", options);
Snackbar.Add("Введите токен", Severity.Warning); var result = await dialog.Result;
return;
}
var request = new SetYandexTokenRequest { Token = _token }; if (!result.Canceled) await LoadStatus();
var response = await Http.PostAsJsonAsync("/api/yandextoken/set", request);
if (response.IsSuccessStatusCode)
{
Snackbar.Add("Токен сохранён", Severity.Success);
await LoadStatus();
_token = "";
}
else
{
Snackbar.Add("Ошибка сохранения токена", Severity.Error);
}
} }
}
public class YandexTokenStatus { public bool HasToken { get; set; } public bool IsValid { get; set; } }
public class SetYandexTokenRequest { public string Token { get; set; } }
}