using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.Api.Contracts;
using Vanguard.Meta;
using Vanguard.State;
namespace Vanguard.UI
{
/// Коллекция игрока и разбор карт в пыль.
public sealed class CollectionView
{
private readonly MetaService _meta;
private readonly PlayerState _player;
private readonly Action _onBack;
private readonly RectTransform _root;
private readonly Text _balances;
private readonly Text _status;
private readonly RectTransform _confirm;
private Text _confirmText;
private RectTransform _content;
private CollectionItemDto _pending;
private bool _loading;
public CollectionView(
Transform parent,
MetaService meta,
PlayerState player,
Action onBack)
{
_meta = meta;
_player = player;
_onBack = onBack;
_root = UiKit.CreatePanel(parent, "CollectionScreen", new Color(0.035f, 0.045f, 0.065f, 1f));
var top = UiKit.CreatePanel(_root, "TopBar", new Color(0.07f, 0.085f, 0.115f, 1f));
top.anchorMin = new Vector2(0f, 1f);
top.anchorMax = new Vector2(1f, 1f);
top.pivot = new Vector2(0.5f, 1f);
top.anchoredPosition = Vector2.zero;
top.sizeDelta = new Vector2(0f, 88f);
UiKit.AddHorizontalLayout(top, 22, 16);
var back = UiKit.CreateButton(top, "Back", "← Назад", () => _onBack(), 18);
UiKit.SetPreferredHeight(back, 44f, 0f);
var title = UiKit.CreateText(top, "Title", "Коллекция", 32, Color.white, TextAnchor.MiddleLeft);
title.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(title, 46f);
_balances = UiKit.CreateText(
top, "Balances", string.Empty, 18,
new Color(0.70f, 0.76f, 0.90f), TextAnchor.MiddleRight);
UiKit.SetPreferredHeight(_balances, 36f);
var body = UiKit.CreatePanel(_root, "Body", new Color(0.035f, 0.045f, 0.065f, 0f));
body.anchorMin = Vector2.zero;
body.anchorMax = Vector2.one;
body.offsetMin = new Vector2(40f, 28f);
body.offsetMax = new Vector2(-40f, -110f);
UiKit.AddVerticalLayout(body, 8, 10);
var hint = UiKit.CreateText(
body,
"Hint",
"Разбор даёт пыль: C 5 · R 10 · RR 25 · RRR 100. SP не разбирается.",
17,
new Color(0.58f, 0.65f, 0.78f),
TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(hint, 26f);
var scroll = UiKit.CreateScrollView(body, "CollectionScroll", out _content, 8f);
var scrollElement = scroll.gameObject.AddComponent();
scrollElement.flexibleHeight = 1f;
scrollElement.minHeight = 200f;
_status = UiKit.CreateText(
body, "Status", string.Empty, 18,
new Color(0.62f, 0.68f, 0.82f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_status, 34f);
_confirm = BuildConfirm(parent);
_confirm.gameObject.SetActive(false);
_root.gameObject.SetActive(false);
_player.Changed += OnPlayerChanged;
}
public void Show()
{
UiKit.SetActive(_root, true);
_confirm.gameObject.SetActive(false);
OnPlayerChanged();
_ = LoadAsync();
}
public void Hide()
{
UiKit.SetActive(_root, false);
_confirm.gameObject.SetActive(false);
}
private RectTransform BuildConfirm(Transform parent)
{
var overlay = UiKit.CreatePanel(parent, "DismantleConfirm", new Color(0f, 0f, 0f, 0.72f));
var card = UiKit.CreateCenteredCard(
overlay, "ConfirmCard", new Vector2(620f, 300f),
new Color(0.08f, 0.10f, 0.14f, 1f));
UiKit.AddVerticalLayout(card, 30, 12);
var title = UiKit.CreateText(card, "Title", "Разобрать карту?", 28, Color.white);
title.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(title, 42f);
_confirmText = UiKit.CreateText(
card, "Text", string.Empty, 19,
new Color(0.72f, 0.78f, 0.92f),
TextAnchor.MiddleCenter);
UiKit.SetPreferredHeight(_confirmText, 110f);
var yes = UiKit.CreateButton(card, "Yes", "Разобрать", OnConfirmDismantle, 20);
UiKit.SetPreferredHeight(yes, 48f);
var no = UiKit.CreateButton(card, "No", "Отмена", HideConfirm, 20);
UiKit.SetPreferredHeight(no, 44f);
overlay.gameObject.SetActive(false);
return overlay;
}
private async Task LoadAsync()
{
if (_loading)
return;
_loading = true;
SetStatus("Загружаем коллекцию…", new Color(0.62f, 0.68f, 0.82f));
try
{
var collection = await _meta.GetCollectionAsync();
Rebuild(collection.Items ?? new List());
SetStatus(
collection.Items == null || collection.Items.Count == 0
? "Коллекция пуста. Пройдите онбординг."
: "Карт в коллекции: " + collection.Items.Sum(item => item.Count) + ".",
new Color(0.62f, 0.68f, 0.82f));
}
catch (ApiException exception)
{
SetStatus(exception.Message, new Color(1f, 0.55f, 0.45f));
}
catch (Exception exception)
{
Debug.LogException(exception);
SetStatus("Не удалось загрузить коллекцию.", new Color(1f, 0.55f, 0.45f));
}
finally
{
_loading = false;
}
}
private void Rebuild(IReadOnlyList items)
{
for (var i = _content.childCount - 1; i >= 0; i--)
UnityEngine.Object.Destroy(_content.GetChild(i).gameObject);
if (items.Count == 0)
return;
foreach (var item in items)
AddRow(item);
}
private void AddRow(CollectionItemDto item)
{
var row = UiKit.CreatePanel(_content, "Item_" + item.PrintingId, new Color(0.07f, 0.085f, 0.115f, 1f));
var rowElement = row.gameObject.AddComponent();
rowElement.preferredHeight = 64f;
UiKit.AddHorizontalLayout(row, 10, 10);
var name = UiKit.CreateText(
row, "Name", item.NameEn, 19, Color.white, TextAnchor.MiddleLeft);
var nameElement = name.gameObject.AddComponent();
nameElement.flexibleWidth = 1f;
nameElement.preferredHeight = 40f;
var printing = UiKit.CreateText(
row, "Printing", item.PrintingId, 16,
new Color(0.58f, 0.65f, 0.78f), TextAnchor.MiddleLeft);
var printingElement = printing.gameObject.AddComponent();
printingElement.preferredWidth = 190f;
printingElement.preferredHeight = 40f;
var rarity = UiKit.CreateText(
row, "Rarity", item.Rarity, 17,
new Color(0.78f, 0.82f, 0.95f));
var rarityElement = rarity.gameObject.AddComponent();
rarityElement.preferredWidth = 64f;
rarityElement.preferredHeight = 40f;
var count = UiKit.CreateText(
row, "Count", "×" + item.Count, 18,
new Color(0.78f, 0.82f, 0.95f));
var countElement = count.gameObject.AddComponent();
countElement.preferredWidth = 54f;
countElement.preferredHeight = 40f;
var canDismantle = item.Rarity != "SP" && item.Count > 0;
var dismantle = UiKit.CreateButton(
row,
"Dismantle",
canDismantle ? "Разобрать 1" : "SP",
() => ShowConfirm(item),
16);
dismantle.interactable = canDismantle;
var dismantleElement = dismantle.gameObject.AddComponent();
dismantleElement.preferredWidth = 150f;
dismantleElement.preferredHeight = 44f;
dismantleElement.flexibleWidth = 0f;
}
private void ShowConfirm(CollectionItemDto item)
{
_pending = item;
_confirmText.text = "«" + item.NameEn + "» (" + item.PrintingId + ")\n"
+ "Вы получите " + DustFor(item.Rarity) + " пыли. Осталось: " + item.Count + ".";
_confirm.SetAsLastSibling();
_confirm.gameObject.SetActive(true);
}
private void HideConfirm()
{
_pending = null;
_confirm.gameObject.SetActive(false);
}
private async void OnConfirmDismantle()
{
if (_pending == null)
return;
var item = _pending;
_confirm.gameObject.SetActive(false);
SetStatus("Разбираем " + item.PrintingId + "…", new Color(0.62f, 0.68f, 0.82f));
try
{
await _meta.DismantleAsync(item.PrintingId, 1);
SetStatus("Разобрано: " + item.PrintingId + ".", new Color(0.45f, 0.85f, 0.55f));
await LoadAsync();
}
catch (ApiException exception)
{
SetStatus(exception.Message, new Color(1f, 0.55f, 0.45f));
}
catch (Exception exception)
{
Debug.LogException(exception);
SetStatus("Не удалось разобрать карту.", new Color(1f, 0.55f, 0.45f));
}
finally
{
_pending = null;
}
}
private static int DustFor(string rarity)
{
switch (rarity)
{
case "C": return 5;
case "R": return 10;
case "RR": return 25;
case "RRR": return 100;
default: return 0;
}
}
private void OnPlayerChanged()
{
_balances.text = "Gold " + _player.Gold + " · Пыль " + _player.Dust
+ " · Токены " + _player.Tokens;
}
private void SetStatus(string text, Color color)
{
_status.text = text ?? string.Empty;
_status.color = color;
}
}
}