VanguardReMaster/client/Assets/Vanguard/Runtime/UI/MetaView.cs

262 lines
9.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.Auth;
using Vanguard.State;
namespace Vanguard.UI
{
/// <summary>Главный экран после входа: профиль, балансы и заглушки разделов.</summary>
public sealed class MetaView : IDisposable
{
private readonly AuthService _auth;
private readonly PlayerState _player;
private readonly Action _onLoggedOut;
private readonly Action _onDecks;
private readonly Action _onStore;
private readonly Action _onHistory;
private readonly Action _onPlay;
private readonly Action _onOnboarding;
private bool _disposed;
private readonly RectTransform _root;
private readonly Text _playerName;
private readonly Text _onboarding;
private readonly Text _gold;
private readonly Text _dust;
private readonly Text _tokens;
private readonly Text _ranked;
private readonly Text _casual;
private readonly Text _record;
private readonly Text _status;
private readonly Button _logout;
private readonly Button _onboardingButton;
private bool _refreshing;
public MetaView(
Transform parent,
AuthService auth,
PlayerState player,
Action onLoggedOut,
Action onDecks,
Action onStore,
Action onHistory,
Action onPlay,
Action onOnboarding)
{
_auth = auth;
_player = player;
_onLoggedOut = onLoggedOut;
_onDecks = onDecks;
_onStore = onStore;
_onHistory = onHistory;
_onPlay = onPlay;
_onOnboarding = onOnboarding;
_root = UiKit.CreatePanel(parent, "MetaScreen", new Color(0.035f, 0.045f, 0.065f, 1f));
var top = UiKit.CreatePanel(_root, "TopBar", new Color(0.07f, 0.085f, 0.115f, 1f));
var topRect = top;
topRect.anchorMin = new Vector2(0f, 1f);
topRect.anchorMax = new Vector2(1f, 1f);
topRect.pivot = new Vector2(0.5f, 1f);
topRect.anchoredPosition = Vector2.zero;
topRect.sizeDelta = new Vector2(0f, 92f);
UiKit.AddHorizontalLayout(top, 22, 16);
var brand = UiKit.CreateText(
top, "Brand", "VANGUARD", 34, new Color(0.86f, 0.90f, 1f), TextAnchor.MiddleLeft);
brand.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(brand, 48f, 0f);
_playerName = UiKit.CreateText(
top, "PlayerName", "…", 20, new Color(0.70f, 0.76f, 0.90f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_playerName, 40f);
_logout = UiKit.CreateButton(top, "Logout", "Выйти", OnLogoutClicked, 18);
UiKit.SetPreferredHeight(_logout, 42f, 0f);
var content = UiKit.CreatePanel(_root, "Content", new Color(0.035f, 0.045f, 0.065f, 0f));
var contentRect = content;
contentRect.anchorMin = Vector2.zero;
contentRect.anchorMax = Vector2.one;
contentRect.offsetMin = new Vector2(48f, 36f);
contentRect.offsetMax = new Vector2(-48f, -116f);
UiKit.AddVerticalLayout(contentRect, 12, 16);
var welcome = UiKit.CreateText(
content, "Welcome", "Личный кабинет", 38, Color.white, TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(welcome, 56f);
_onboarding = UiKit.CreateText(
content, "Onboarding", string.Empty, 18,
new Color(1f, 0.76f, 0.38f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_onboarding, 28f);
var stats = UiKit.CreatePanel(content, "Stats", new Color(0.07f, 0.085f, 0.115f, 1f));
UiKit.SetPreferredHeight(stats, 130f);
UiKit.AddHorizontalLayout(stats, 18, 14);
_gold = AddStat(stats, "Gold");
_dust = AddStat(stats, "Пыль");
_tokens = AddStat(stats, "Токены");
_ranked = AddStat(stats, "Ranked MMR");
_casual = AddStat(stats, "Casual MMR");
var actions = UiKit.CreatePanel(content, "Actions", new Color(0.07f, 0.085f, 0.115f, 1f));
UiKit.SetPreferredHeight(actions, 96f);
UiKit.AddHorizontalLayout(actions, 18, 14);
AddAction(actions, "Коллекция", _onDecks);
AddAction(actions, "Магазин", _onStore);
AddAction(actions, "История", _onHistory);
AddAction(actions, "В бой", _onPlay);
var lower = UiKit.CreatePanel(content, "Lower", new Color(0.07f, 0.085f, 0.115f, 1f));
UiKit.SetPreferredHeight(lower, 220f, 1f);
UiKit.AddVerticalLayout(lower, 20, 8);
_record = UiKit.CreateText(
lower, "Record", string.Empty, 20,
new Color(0.72f, 0.78f, 0.92f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_record, 28f);
_status = UiKit.CreateText(
lower, "Status", string.Empty, 18,
new Color(0.62f, 0.68f, 0.82f), TextAnchor.UpperLeft);
UiKit.SetPreferredHeight(_status, 70f);
_onboardingButton = UiKit.CreateButton(
lower, "OnboardingButton", "Выбрать триал-деку", () => _onOnboarding(), 20);
UiKit.SetPreferredHeight(_onboardingButton, 46f);
_player.Changed += UpdateTexts;
_root.gameObject.SetActive(false);
}
public void Show()
{
UiKit.SetActive(_root, true);
UpdateTexts();
_ = RefreshAsync();
}
public void Hide() => UiKit.SetActive(_root, false);
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
_player.Changed -= UpdateTexts;
}
private static Text AddStat(Transform parent, string caption)
{
var card = UiKit.CreatePanel(parent, "Stat_" + caption, new Color(0.09f, 0.11f, 0.15f, 1f));
UiKit.AddVerticalLayout(card, 12, 4);
var element = card.gameObject.AddComponent<LayoutElement>();
element.flexibleWidth = 1f;
element.preferredHeight = 100f;
var label = UiKit.CreateText(
card, "Caption", caption, 16, new Color(0.58f, 0.65f, 0.78f));
UiKit.SetPreferredHeight(label, 22f);
var value = UiKit.CreateText(
card, "Value", "—", 30, Color.white);
value.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(value, 40f);
return value;
}
private static Button AddAction(Transform parent, string caption, Action onClick)
{
var button = UiKit.CreateButton(parent, "Action_" + caption, caption, () => onClick(), 20);
var element = button.gameObject.AddComponent<LayoutElement>();
element.flexibleWidth = 1f;
element.preferredHeight = 56f;
return button;
}
private async Task RefreshAsync()
{
if (_refreshing)
return;
_refreshing = true;
SetStatus("Обновляем профиль…", new Color(0.62f, 0.68f, 0.82f));
try
{
await _auth.RefreshMeAsync();
if (_disposed)
return;
SetStatus("Профиль обновлён.", new Color(0.45f, 0.85f, 0.55f));
}
catch (ApiException exception) when (exception.StatusCode == 401)
{
if (!_disposed)
_onLoggedOut();
}
catch (Exception exception)
{
Debug.LogException(exception);
SetStatus("Не удалось обновить профиль. Сервер недоступен?", new Color(1f, 0.60f, 0.45f));
}
finally
{
_refreshing = false;
}
}
private void UpdateTexts()
{
if (_disposed)
return;
_playerName.text = string.IsNullOrEmpty(_player.UserName)
? "…"
: _player.UserName;
_gold.text = _player.Gold.ToString();
_dust.text = _player.Dust.ToString();
_tokens.text = _player.Tokens.ToString();
_ranked.text = _player.RankedMmr.ToString();
_casual.text = _player.CasualMmr.ToString();
_record.text = "Матчей: " + _player.Matches + " · побед: " + _player.Wins
+ " · XP: " + _player.Xp;
_onboarding.text = _player.OnboardingCompleted
? "Онбординг завершён: " + (_player.SelectedTrialDeckId ?? "—")
: "Онбординг не завершён: выберите стартовую триал-деку.";
_onboardingButton.gameObject.SetActive(!_player.OnboardingCompleted);
}
private void SetStatus(string text, Color color)
{
if (_disposed || _status == null)
return;
_status.text = text ?? string.Empty;
_status.color = color;
}
private async void OnLogoutClicked()
{
_logout.interactable = false;
await _auth.LogoutAsync();
if (_disposed)
return;
_logout.interactable = true;
_onLoggedOut();
}
}
}