using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; using Vanguard.Api; using Vanguard.Api.Contracts; using Vanguard.Auth; using Vanguard.Meta; namespace Vanguard.UI { /// История матчей в Lobby и вход в реплей. public sealed class HistoryView { private readonly MetaService _meta; private readonly AuthService _auth; private readonly Action _onBack; private readonly RectTransform _root; private readonly Text _status; private readonly RectTransform _content; private readonly ReplayView _replay; private bool _loading; public HistoryView( Transform parent, MetaService meta, AuthService auth, Action onBack) { _meta = meta; _auth = auth; _onBack = onBack; _root = UiKit.CreatePanel(parent, "HistoryScreen", new Color(0.018f, 0.03f, 0.06f, 0.96f)); var top = UiKit.CreatePanel(_root, "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, 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); var hint = UiKit.CreateText( top, "Hint", "Только ваши матчи · реплей доступен участникам", 16, new Color(0.60f, 0.68f, 0.84f), TextAnchor.MiddleRight); UiKit.SetPreferredHeight(hint, 36f); var body = UiKit.CreatePanel(_root, "Body", new Color(0f, 0f, 0f, 0f)); body.anchorMin = Vector2.zero; body.anchorMax = Vector2.one; body.offsetMin = new Vector2(44f, 30f); body.offsetMax = new Vector2(-44f, -110f); UiKit.AddVerticalLayout(body, 8, 10); var scroll = UiKit.CreateScrollView(body, "HistoryScroll", 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); _replay = new ReplayView(_root, _meta, HideReplay); _root.gameObject.SetActive(false); } public void Show() { UiKit.SetActive(_root, true); _replay.Hide(); _ = LoadAsync(); } public void Hide() { _replay.Hide(); UiKit.SetActive(_root, false); } private async Task LoadAsync() { if (_loading) return; _loading = true; SetStatus("Загружаем историю…", new Color(0.62f, 0.68f, 0.82f)); ClearChildren(_content); try { await _auth.EnsureAccessAsync(); var history = await _meta.GetHistoryAsync(); if (_root == null || !_root.gameObject.activeSelf) return; Build(history.Items); SetStatus( history.Items == null || history.Items.Count == 0 ? "Матчей пока нет." : "Матчей: " + history.Items.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 Build(IReadOnlyList items) { ClearChildren(_content); if (items == null || items.Count == 0) return; foreach (var item in items) AddRow(item); } private void AddRow(MatchHistoryDto item) { var row = UiKit.CreatePanel(_content, "Match_" + item.MatchId, new Color(0.07f, 0.09f, 0.14f, 1f)); var rowElement = row.gameObject.AddComponent(); rowElement.preferredHeight = 96f; UiKit.AddHorizontalLayout(row, 14, 14); var info = UiKit.CreatePanel(row, "Info", new Color(0f, 0f, 0f, 0f)); var infoElement = info.gameObject.AddComponent(); infoElement.flexibleWidth = 1f; infoElement.preferredHeight = 64f; UiKit.AddVerticalLayout(info, 0, 2); var opponent = UiKit.CreateText( info, "Opponent", (item.Result == "win" ? "Победа" : item.Result == "loss" ? "Поражение" : "Ничья") + " против " + item.OpponentName, 21, item.Result == "win" ? new Color(0.45f, 0.85f, 0.55f) : new Color(1f, 0.62f, 0.48f), TextAnchor.MiddleLeft); opponent.fontStyle = FontStyle.Bold; UiKit.SetPreferredHeight(opponent, 28f); var detail = UiKit.CreateText( info, "Detail", item.Mode + " · " + item.FinishReason + " · " + item.PlayedAt.ToLocalTime().ToString("dd.MM.yyyy HH:mm"), 16, new Color(0.60f, 0.68f, 0.84f), TextAnchor.MiddleLeft); UiKit.SetPreferredHeight(detail, 24f); var rewards = UiKit.CreateText( row, "Rewards", "Gold " + item.Gold + " · XP " + item.Xp + "\nMMR " + item.MmrBefore + " → " + item.MmrAfter, 16, new Color(0.72f, 0.78f, 0.92f)); var rewardsElement = rewards.gameObject.AddComponent(); rewardsElement.preferredWidth = 210f; rewardsElement.preferredHeight = 56f; var replay = UiKit.CreateButton( row, "Replay", item.ReplayAvailable ? "Реплей" : "Нет реплея", () => _replay.Show(item.MatchId), 17); replay.interactable = item.ReplayAvailable; var replayElement = replay.gameObject.AddComponent(); replayElement.preferredWidth = 130f; replayElement.preferredHeight = 46f; replayElement.flexibleWidth = 0f; } private void HideReplay() { _replay.Hide(); } private void SetStatus(string text, Color color) { if (_status == null) return; _status.text = text ?? string.Empty; _status.color = color; } private static void ClearChildren(Transform parent) { for (var i = parent.childCount - 1; i >= 0; i--) UnityEngine.Object.Destroy(parent.GetChild(i).gameObject); } } }