using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.Api.Contracts;
using Vanguard.Auth;
using Vanguard.Meta;
namespace Vanguard.UI
{
///
/// Декбилдер в духе HS: коллекция в центре, узкая колонка колод/карт справа.
/// Список колод и редактор используют один и тот же блок коллекции.
///
public sealed class DeckBuilderView
{
private readonly MetaService _meta;
private readonly AuthService _auth;
private readonly Action _onBack;
private readonly Action _onPlay;
private readonly RectTransform _root;
private readonly RectTransform _listView;
private readonly RectTransform _editorView;
private RectTransform _deckListContent;
private RectTransform _listCollectionContent;
private RectTransform _editorCollectionContent;
private RectTransform _deckCardContent;
private InputField _nameInput;
private Text _listStatus;
private Text _editorStatus;
private Text _stats;
private Text _deckCount;
private Text _filterSummary;
private RectTransform _filterOverlay;
private RectTransform _clanContent;
private RectTransform _confirmOverlay;
private Text _confirmText;
private DeckDto _pendingDelete;
private RectTransform _cardOverlay;
private Image _cardArt;
private Text _cardArtName;
private Text _cardTitle;
private Text _cardSubtitle;
private Text _cardStats;
private Text _cardAbilities;
private Text _cardOwned;
private Text _cardStatus;
private Button _dismantleButton;
private Button _craftButton;
private CollectionItemDto _selectedItem;
private CardCatalogItemDto _selectedMeta;
private readonly List _decks = new List();
private readonly List _collection = new List();
private readonly Dictionary _catalog =
new Dictionary(StringComparer.Ordinal);
private readonly List _cards = new List();
private readonly Dictionary _listCountTexts =
new Dictionary(StringComparer.Ordinal);
private readonly Dictionary _editorCountTexts =
new Dictionary(StringComparer.Ordinal);
private DeckDto _editing;
private string _filterClan = "Все";
private string _filterTrigger = "Все";
private int _filterGrade = -1;
private bool _loading;
private bool _busy;
public DeckBuilderView(
Transform parent,
MetaService meta,
AuthService auth,
Action onBack,
Action onPlay)
{
_meta = meta;
_auth = auth;
_onBack = onBack;
_onPlay = onPlay;
_root = UiKit.CreatePanel(parent, "DeckBuilderScreen", new Color(0.018f, 0.03f, 0.06f, 0.97f));
_listView = BuildListView();
_editorView = BuildEditorView();
_filterOverlay = BuildFilterOverlay();
_confirmOverlay = BuildDeleteConfirm();
_cardOverlay = BuildCardOverlay();
_listView.gameObject.SetActive(false);
_editorView.gameObject.SetActive(false);
_filterOverlay.gameObject.SetActive(false);
_confirmOverlay.gameObject.SetActive(false);
_cardOverlay.gameObject.SetActive(false);
_root.gameObject.SetActive(false);
}
public void Show()
{
UiKit.SetActive(_root, true);
ShowList();
_ = LoadAsync();
}
public void Hide()
{
_filterOverlay.gameObject.SetActive(false);
_confirmOverlay.gameObject.SetActive(false);
_cardOverlay.gameObject.SetActive(false);
_root.gameObject.SetActive(false);
}
private RectTransform BuildListView()
{
var view = UiKit.CreatePanel(_root, "DeckList", new Color(0.018f, 0.03f, 0.06f, 0.97f));
var top = BuildTopBar(view);
var back = UiKit.CreateButton(top, "Back", "← В лобби", () => _onBack(), 17);
SetFixedSize(back, 120f, 44f);
var title = UiKit.CreateText(top, "Title", "Коллекция", 28, Color.white, TextAnchor.MiddleLeft);
title.fontStyle = FontStyle.Bold;
SetFixedSize(title, 150f, 44f);
_filterSummary = UiKit.CreateText(
top, "FilterSummary", "Все карты", 16,
new Color(0.60f, 0.68f, 0.84f), TextAnchor.MiddleLeft);
SetFlexible(_filterSummary, 1f, 44f);
var filters = UiKit.CreateButton(top, "Filters", "Фильтры", OpenFilters, 17);
SetFixedSize(filters, 110f, 44f);
var reset = UiKit.CreateButton(top, "ResetFilters", "Сброс", ResetFilters, 17);
SetFixedSize(reset, 90f, 44f);
var create = UiKit.CreateButton(top, "Create", "Создать колоду", NewDeck, 17);
SetFixedSize(create, 180f, 44f);
var body = UiKit.CreatePanel(view, "Body", new Color(0f, 0f, 0f, 0f));
body.anchorMin = Vector2.zero;
body.anchorMax = Vector2.one;
body.offsetMin = new Vector2(34f, 28f);
body.offsetMax = new Vector2(-34f, -108f);
UiKit.AddHorizontalLayout(body, 0, 14);
var collectionArea = UiKit.CreatePanel(
body, "CollectionArea", new Color(0.04f, 0.06f, 0.10f, 0.55f));
var collectionElement = collectionArea.gameObject.AddComponent();
collectionElement.flexibleWidth = 1f;
collectionElement.flexibleHeight = 1f;
collectionElement.minHeight = 300f;
UiKit.AddVerticalLayout(collectionArea, 8, 6);
var scroll = UiKit.CreateGridScrollView(
collectionArea,
"CollectionGrid",
new Vector2(174f, 238f),
new Vector2(10f, 10f),
out _listCollectionContent);
var scrollElement = scroll.gameObject.AddComponent();
scrollElement.flexibleHeight = 1f;
scrollElement.minHeight = 220f;
_listStatus = UiKit.CreateText(
collectionArea, "Status", string.Empty, 16,
new Color(0.62f, 0.68f, 0.82f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_listStatus, 32f);
var deckArea = UiKit.CreatePanel(
body, "DeckArea", new Color(0.04f, 0.06f, 0.10f, 0.85f));
var deckElement = deckArea.gameObject.AddComponent();
deckElement.preferredWidth = 300f;
deckElement.minWidth = 280f;
deckElement.flexibleWidth = 0f;
deckElement.flexibleHeight = 1f;
deckElement.minHeight = 300f;
UiKit.AddVerticalLayout(deckArea, 10, 6);
var deckTitle = UiKit.CreateText(
deckArea, "Title", "Мои колоды", 20, Color.white, TextAnchor.MiddleLeft);
deckTitle.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(deckTitle, 30f);
var deckScroll = UiKit.CreateScrollView(deckArea, "DeckListScroll", out _deckListContent, 8f);
var deckScrollElement = deckScroll.gameObject.AddComponent();
deckScrollElement.flexibleHeight = 1f;
deckScrollElement.minHeight = 200f;
var hint = UiKit.CreateText(
deckArea, "Hint", "Нажмите на колоду,\nчтобы открыть редактор.", 14,
new Color(0.58f, 0.66f, 0.80f), TextAnchor.MiddleLeft);
hint.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(hint, 46f);
return view;
}
private RectTransform BuildEditorView()
{
var view = UiKit.CreatePanel(_root, "DeckEditor", new Color(0.018f, 0.03f, 0.06f, 0.97f));
var top = BuildTopBar(view);
var back = UiKit.CreateButton(top, "Back", "← Коллекция", BackToList, 17);
SetFixedSize(back, 120f, 44f);
_nameInput = UiKit.CreateInput(top, "Name", "Название колоды");
SetFlexible(_nameInput, 0.7f, 46f);
var filters = UiKit.CreateButton(top, "Filters", "Фильтры", OpenFilters, 17);
SetFixedSize(filters, 110f, 44f);
var reset = UiKit.CreateButton(top, "ResetFilters", "Сброс", ResetFilters, 17);
SetFixedSize(reset, 90f, 44f);
_stats = UiKit.CreateText(
top, "Stats", string.Empty, 15,
new Color(0.72f, 0.78f, 0.92f), TextAnchor.MiddleLeft);
_stats.horizontalOverflow = HorizontalWrapMode.Wrap;
SetFlexible(_stats, 1.4f, 50f);
var save = UiKit.CreateButton(top, "Save", "Сохранить", SaveDeck, 17);
SetFixedSize(save, 120f, 44f);
var duel = UiKit.CreateButton(top, "Duel", "В бой", PlayDeck, 17);
SetFixedSize(duel, 90f, 44f);
var delete = UiKit.CreateButton(top, "Delete", "Удалить", RequestDeleteCurrent, 17);
SetFixedSize(delete, 100f, 44f);
var body = UiKit.CreatePanel(view, "Body", new Color(0f, 0f, 0f, 0f));
body.anchorMin = Vector2.zero;
body.anchorMax = Vector2.one;
body.offsetMin = new Vector2(34f, 28f);
body.offsetMax = new Vector2(-34f, -108f);
UiKit.AddHorizontalLayout(body, 0, 14);
var collectionArea = UiKit.CreatePanel(
body, "CollectionArea", new Color(0.04f, 0.06f, 0.10f, 0.55f));
var collectionElement = collectionArea.gameObject.AddComponent();
collectionElement.flexibleWidth = 1f;
collectionElement.flexibleHeight = 1f;
collectionElement.minHeight = 300f;
UiKit.AddVerticalLayout(collectionArea, 8, 6);
var scroll = UiKit.CreateGridScrollView(
collectionArea,
"CollectionGrid",
new Vector2(174f, 238f),
new Vector2(10f, 10f),
out _editorCollectionContent);
var scrollElement = scroll.gameObject.AddComponent();
scrollElement.flexibleHeight = 1f;
scrollElement.minHeight = 220f;
_editorStatus = UiKit.CreateText(
collectionArea, "Status", string.Empty, 16,
new Color(0.62f, 0.68f, 0.82f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_editorStatus, 32f);
var deckArea = UiKit.CreatePanel(
body, "DeckArea", new Color(0.04f, 0.06f, 0.10f, 0.85f));
var deckElement = deckArea.gameObject.AddComponent();
deckElement.preferredWidth = 300f;
deckElement.minWidth = 280f;
deckElement.flexibleWidth = 0f;
deckElement.flexibleHeight = 1f;
deckElement.minHeight = 300f;
UiKit.AddVerticalLayout(deckArea, 10, 6);
_deckCount = UiKit.CreateText(
deckArea, "DeckCount", "Колода: 0/50", 19, Color.white, TextAnchor.MiddleLeft);
_deckCount.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(_deckCount, 28f);
var deckScroll = UiKit.CreateScrollView(deckArea, "DeckCardScroll", out _deckCardContent, 6f);
var deckScrollElement = deckScroll.gameObject.AddComponent();
deckScrollElement.flexibleHeight = 1f;
deckScrollElement.minHeight = 200f;
var hint = UiKit.CreateText(
deckArea, "Hint", "ЛКМ — убрать копию,\nПКМ — посмотреть карту.", 14,
new Color(0.58f, 0.66f, 0.80f), TextAnchor.MiddleLeft);
hint.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(hint, 46f);
return view;
}
private RectTransform BuildTopBar(RectTransform view)
{
var top = UiKit.CreatePanel(view, "TopBar", new Color(0.06f, 0.08f, 0.13f, 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, 18, 12);
return top;
}
private RectTransform BuildFilterOverlay()
{
var overlay = UiKit.CreatePanel(_root, "FilterOverlay", new Color(0f, 0f, 0f, 0.78f));
var card = UiKit.CreateCenteredCard(
overlay, "FilterCard", new Vector2(860f, 820f),
new Color(0.06f, 0.08f, 0.13f, 1f));
UiKit.AddVerticalLayout(card, 26, 10);
var title = UiKit.CreateText(card, "Title", "Фильтры коллекции", 28, Color.white);
title.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(title, 40f);
AddFilterSection(card, "Ранг", new[] { "Все", "0", "1", "2", "3" }, OnGradeFilter);
AddFilterSection(card, "Триггер", new[] { "Все", "None", "Critical", "Draw", "Stand", "Heal" }, OnTriggerFilter);
var clanTitle = UiKit.CreateText(
card, "ClanTitle", "Клан", 17, new Color(0.66f, 0.74f, 0.90f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(clanTitle, 24f);
var clanScroll = UiKit.CreateScrollView(card, "ClanScroll", out _clanContent, 4f);
var clanElement = clanScroll.gameObject.AddComponent();
clanElement.flexibleHeight = 1f;
clanElement.minHeight = 150f;
var close = UiKit.CreateButton(card, "Close", "Готово", CloseFilters, 20);
UiKit.SetPreferredHeight(close, 48f);
return overlay;
}
private void RebuildClanFilters()
{
ClearChildren(_clanContent);
AddClanButton(_clanContent, "Все");
foreach (var clan in _catalog.Values.Select(item => item.Clan).Distinct().OrderBy(item => item))
AddClanButton(_clanContent, clan);
}
private RectTransform BuildDeleteConfirm()
{
var overlay = UiKit.CreatePanel(
_root, "DeleteDeckConfirm", new Color(0f, 0f, 0f, 0.78f));
var card = UiKit.CreateCenteredCard(
overlay, "ConfirmCard", new Vector2(640f, 300f),
new Color(0.06f, 0.08f, 0.13f, 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));
UiKit.SetPreferredHeight(_confirmText, 70f);
var yes = UiKit.CreateButton(card, "Yes", "Удалить", ConfirmDelete, 20);
UiKit.SetPreferredHeight(yes, 48f);
var no = UiKit.CreateButton(card, "No", "Отмена", CancelDelete, 20);
UiKit.SetPreferredHeight(no, 44f);
return overlay;
}
private RectTransform BuildCardOverlay()
{
var overlay = UiKit.CreatePanel(_root, "CardOverlay", new Color(0f, 0f, 0f, 0.82f));
var card = UiKit.CreateCenteredCard(
overlay, "CardView", new Vector2(1040f, 660f),
new Color(0.05f, 0.07f, 0.11f, 1f));
var body = UiKit.CreatePanel(card, "Body", new Color(0f, 0f, 0f, 0f));
body.anchorMin = Vector2.zero;
body.anchorMax = Vector2.one;
body.offsetMin = new Vector2(26f, 26f);
body.offsetMax = new Vector2(-26f, -26f);
UiKit.AddHorizontalLayout(body, 0, 22);
var art = UiKit.CreatePanel(body, "Art", new Color(0.2f, 0.3f, 0.5f, 1f));
SetFixedSize(art, 360f, 540f);
_cardArt = art.GetComponent();
_cardArtName = UiKit.CreateText(
art, "ArtName", string.Empty, 18,
new Color(1f, 1f, 1f, 0.92f), TextAnchor.MiddleCenter);
UiKit.Stretch(_cardArtName.rectTransform);
_cardArtName.rectTransform.offsetMin = new Vector2(14f, 16f);
_cardArtName.rectTransform.offsetMax = new Vector2(-14f, -16f);
_cardArtName.horizontalOverflow = HorizontalWrapMode.Wrap;
var info = UiKit.CreatePanel(body, "Info", new Color(0f, 0f, 0f, 0f));
var infoElement = info.gameObject.AddComponent();
infoElement.flexibleWidth = 1f;
infoElement.flexibleHeight = 1f;
UiKit.AddVerticalLayout(info, 4, 6);
_cardTitle = UiKit.CreateText(
info, "Title", string.Empty, 30, Color.white, TextAnchor.MiddleLeft);
_cardTitle.fontStyle = FontStyle.Bold;
_cardTitle.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(_cardTitle, 44f);
_cardSubtitle = UiKit.CreateText(
info, "Subtitle", string.Empty, 16,
new Color(0.62f, 0.70f, 0.84f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_cardSubtitle, 26f);
_cardStats = UiKit.CreateText(
info, "Stats", string.Empty, 15,
new Color(0.72f, 0.78f, 0.92f), TextAnchor.UpperLeft);
_cardStats.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(_cardStats, 88f);
var abilitiesCaption = UiKit.CreateText(
info, "AbilitiesCaption", "Способности", 16,
new Color(0.66f, 0.74f, 0.90f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(abilitiesCaption, 24f);
_cardAbilities = UiKit.CreateText(
info, "Abilities", string.Empty, 15,
new Color(0.82f, 0.86f, 0.96f), TextAnchor.UpperLeft);
_cardAbilities.horizontalOverflow = HorizontalWrapMode.Wrap;
var abilitiesElement = _cardAbilities.gameObject.AddComponent();
abilitiesElement.flexibleHeight = 1f;
abilitiesElement.minHeight = 100f;
_cardOwned = UiKit.CreateText(
info, "Owned", string.Empty, 15,
new Color(0.98f, 0.82f, 0.42f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(_cardOwned, 24f);
_cardStatus = UiKit.CreateText(
info, "Status", string.Empty, 14,
new Color(0.62f, 0.68f, 0.82f), TextAnchor.UpperLeft);
_cardStatus.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(_cardStatus, 38f);
var actions = UiKit.CreatePanel(info, "Actions", new Color(0f, 0f, 0f, 0f));
UiKit.SetPreferredHeight(actions, 50f);
UiKit.AddHorizontalLayout(actions, 0, 8);
_dismantleButton = UiKit.CreateButton(
actions, "Dismantle", "Разобрать", DismantleSelected, 16);
SetFixedSize(_dismantleButton, 225f, 46f);
_craftButton = UiKit.CreateButton(
actions, "Craft", "Скрафтить", CraftSelected, 16);
SetFixedSize(_craftButton, 225f, 46f);
var close = UiKit.CreateButton(actions, "Close", "Закрыть", CloseCardOverlay, 16);
SetFixedSize(close, 110f, 46f);
return overlay;
}
private void AddRightClick(GameObject target, string printingId, CardCatalogItemDto meta)
{
var trigger = target.GetComponent()
?? target.AddComponent();
var entry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
entry.callback.AddListener(data =>
{
if (data is PointerEventData pointer
&& pointer.button == PointerEventData.InputButton.Right)
{
ShowCardOverlay(printingId, meta);
}
});
trigger.triggers.Add(entry);
}
private void ShowCardOverlay(string printingId, CardCatalogItemDto meta)
{
if (meta == null)
return;
_selectedMeta = meta;
_selectedItem = _collection.Find(item => item.PrintingId == printingId);
_cardStatus.text = string.Empty;
UpdateCardOverlay();
_cardOverlay.SetAsLastSibling();
_cardOverlay.gameObject.SetActive(true);
}
private void UpdateCardOverlay()
{
if (_selectedMeta == null)
return;
var meta = _selectedMeta;
_cardArt.color = ClanColor(meta.Clan);
_cardArtName.text = meta.NameEn;
_cardTitle.text = meta.NameEn;
_cardSubtitle.text = (string.IsNullOrEmpty(meta.NameRu) ? string.Empty : meta.NameRu + " · ")
+ meta.Clan + " · G" + meta.Grade;
_cardStats.text = "Тип: " + meta.Type + " · Редкость: " + meta.Rarity + "\n"
+ "Power " + meta.Power + " · Shield " + meta.Shield + " · Critical " + meta.Critical + "\n"
+ "Триггер: " + meta.Trigger
+ " · Sentinel: " + (meta.IsSentinel ? "да" : "нет")
+ " · Boost: " + (meta.HasBoost ? "да" : "нет")
+ " · Intercept: " + (meta.HasIntercept ? "да" : "нет") + "\n"
+ "Принт: " + meta.PrintingId;
_cardAbilities.text = string.IsNullOrWhiteSpace(meta.TextRu)
? (string.IsNullOrWhiteSpace(meta.TextEn) ? "Текст способности отсутствует." : meta.TextEn)
: meta.TextRu;
_cardOwned.text = "В коллекции: ×" + (_selectedItem != null ? _selectedItem.Count : 0)
+ " · в колоде: " + UsedByName(meta.NameId);
var canChange = CanChange(meta.Rarity);
_dismantleButton.interactable = canChange && !_busy
&& _selectedItem != null && _selectedItem.Count > 0;
_craftButton.interactable = canChange && !_busy;
SetButtonLabel(
_dismantleButton,
canChange ? "Разобрать (+" + DustFor(meta.Rarity) + " пыли)" : "Нельзя разобрать");
SetButtonLabel(
_craftButton,
canChange ? "Скрафтить (−" + CraftCostFor(meta.Rarity) + " пыли)" : "Нельзя скрафтить");
}
private static bool CanChange(string rarity) =>
rarity == "C" || rarity == "R" || rarity == "RR" || rarity == "RRR";
private async void DismantleSelected()
{
if (_busy || _selectedItem == null || _selectedItem.Count <= 0
|| _selectedMeta == null || !CanChange(_selectedMeta.Rarity))
return;
var printingId = _selectedItem.PrintingId;
_busy = true;
UpdateCardOverlay();
_cardStatus.text = "Разбираем…";
_cardStatus.color = new Color(0.62f, 0.68f, 0.82f);
try
{
await _auth.EnsureAccessAsync();
await _meta.DismantleAsync(printingId, 1);
await ReloadCollectionAsync(printingId);
SetCardStatus("Карта разобрана.", false);
}
catch (ApiException exception)
{
SetCardStatus(exception.Message, true);
}
catch (Exception exception)
{
Debug.LogException(exception);
SetCardStatus("Не удалось разобрать карту.", true);
}
finally
{
_busy = false;
UpdateCardOverlay();
}
}
private async void CraftSelected()
{
if (_busy || _selectedMeta == null || !CanChange(_selectedMeta.Rarity))
return;
var printingId = _selectedMeta.PrintingId;
_busy = true;
UpdateCardOverlay();
_cardStatus.text = "Крафтим…";
_cardStatus.color = new Color(0.62f, 0.68f, 0.82f);
try
{
await _auth.EnsureAccessAsync();
await _meta.CraftAsync(printingId);
await ReloadCollectionAsync(printingId);
SetCardStatus("Карта скрафчена.", false);
}
catch (ApiException exception)
{
SetCardStatus(exception.Message, true);
}
catch (Exception exception)
{
Debug.LogException(exception);
SetCardStatus("Не удалось скрафтить карту.", true);
}
finally
{
_busy = false;
UpdateCardOverlay();
}
}
private async Task ReloadCollectionAsync(string printingId)
{
var collection = await _meta.GetCollectionAsync();
_collection.Clear();
_collection.AddRange(collection.Items ?? new List());
RebuildCollectionGrids();
_selectedItem = _collection.Find(item => item.PrintingId == printingId);
if (_selectedItem == null)
{
_cardOverlay.gameObject.SetActive(false);
_listStatus.text = "Карт в коллекции: " + _collection.Count + ".";
}
else
{
UpdateCardOverlay();
}
}
private void SetCardStatus(string text, bool error)
{
_cardStatus.text = text;
_cardStatus.color = error
? new Color(1f, 0.55f, 0.45f)
: new Color(0.45f, 0.85f, 0.55f);
}
private void CloseCardOverlay()
{
_selectedItem = null;
_selectedMeta = null;
_cardOverlay.gameObject.SetActive(false);
}
private void AddFilterSection(Transform parent, string title, string[] labels, Action onSelected)
{
var caption = UiKit.CreateText(
parent, "Caption_" + title, title, 17,
new Color(0.66f, 0.74f, 0.90f), TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(caption, 24f);
var row = UiKit.CreatePanel(parent, "Row_" + title, new Color(0f, 0f, 0f, 0f));
UiKit.SetPreferredHeight(row, 44f);
UiKit.AddHorizontalLayout(row, 0, 6);
foreach (var label in labels)
{
var captured = label;
var button = UiKit.CreateButton(
row, "Filter_" + label, label, () => onSelected(captured), 16);
UiKit.SetPreferredHeight(button, 40f);
}
}
private void AddClanButton(Transform parent, string clan)
{
var captured = clan;
var button = UiKit.CreateButton(
parent, "Clan_" + clan, clan, () => OnClanFilter(captured), 16);
UiKit.SetPreferredHeight(button, 40f);
}
private async Task LoadAsync()
{
if (_loading)
return;
_loading = true;
_listStatus.text = "Загружаем коллекцию и колоды…";
_listStatus.color = new Color(0.62f, 0.68f, 0.82f);
ClearChildren(_deckListContent);
try
{
await _auth.EnsureAccessAsync();
var collection = await _meta.GetCollectionAsync();
var catalog = await _meta.GetCatalogAsync();
var decks = await _meta.GetDecksAsync();
if (!_root.gameObject.activeSelf)
return;
_collection.Clear();
_collection.AddRange(collection.Items ?? new List());
_catalog.Clear();
foreach (var item in catalog)
_catalog[item.PrintingId] = item;
RebuildClanFilters();
_decks.Clear();
_decks.AddRange(decks);
BuildDeckList();
RebuildCollectionGrids();
_listStatus.text = _decks.Count == 0
? "Колод пока нет. Создайте первую. ПКМ по карте — подробности."
: "Карт в коллекции: " + _collection.Count + " · ПКМ по карте — подробности.";
}
catch (ApiException exception)
{
_listStatus.text = exception.Message;
_listStatus.color = new Color(1f, 0.55f, 0.45f);
}
catch (Exception exception)
{
Debug.LogException(exception);
_listStatus.text = "Не удалось загрузить декбилдер.";
_listStatus.color = new Color(1f, 0.55f, 0.45f);
}
finally
{
_loading = false;
}
}
private void BuildDeckList()
{
ClearChildren(_deckListContent);
if (_decks.Count == 0)
{
var empty = UiKit.CreateText(
_deckListContent, "Empty", "Нет колод", 16,
new Color(0.58f, 0.66f, 0.80f));
UiKit.SetPreferredHeight(empty, 90f);
return;
}
foreach (var deck in _decks)
{
var row = UiKit.CreatePanel(
_deckListContent, "DeckRow_" + deck.Id, new Color(0.08f, 0.11f, 0.17f, 1f));
var rowElement = row.gameObject.AddComponent();
rowElement.preferredHeight = 76f;
UiKit.AddVerticalLayout(row, 10, 2);
var button = row.gameObject.AddComponent