733 lines
27 KiB
C#
733 lines
27 KiB
C#
using System;
|
||
using System.Threading.Tasks;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using Vanguard.Api;
|
||
using Vanguard.App;
|
||
using Vanguard.Auth;
|
||
using Vanguard.State;
|
||
|
||
namespace Vanguard.UI
|
||
{
|
||
/// <summary>
|
||
/// Главный экран после входа: профиль и балансы, вход в бой/колоды/магазин,
|
||
/// заглушки разделов без серверной части и гамбургер-меню.
|
||
/// </summary>
|
||
public sealed class LobbyView : IDisposable
|
||
{
|
||
public const string RootName = "LobbyScreen";
|
||
|
||
private const float Margin = 24f;
|
||
private const float LeftWidth = 560f;
|
||
private const float RightWidth = 336f;
|
||
private const float Gutter = 16f;
|
||
private const float ContentTop = 112f;
|
||
private const float BottomMargin = 24f;
|
||
private const float BalanceHeight = 88f;
|
||
|
||
private static readonly Color PanelFill = new Color(0.024f, 0.058f, 0.15f, 0.92f);
|
||
private static readonly Color PanelFillSoft = new Color(0.035f, 0.08f, 0.19f, 0.55f);
|
||
private static readonly Color Border = new Color(0.18f, 0.49f, 1f, 0.55f);
|
||
private static readonly Color BorderStrong = new Color(0.34f, 0.72f, 1f, 0.9f);
|
||
private static readonly Color TextPrimary = new Color(0.88f, 0.93f, 1f);
|
||
private static readonly Color TextMuted = new Color(0.58f, 0.69f, 0.88f);
|
||
private static readonly Color TextDim = new Color(0.44f, 0.55f, 0.75f);
|
||
private static readonly Color Accent = new Color(0.37f, 0.69f, 1f);
|
||
|
||
private readonly AuthService _auth;
|
||
private readonly PlayerState _player;
|
||
private readonly Action _onLoggedOut;
|
||
private readonly Action _onStore;
|
||
private readonly PlayerTopBar _topBar;
|
||
private readonly StatusTicker _ticker;
|
||
|
||
private readonly RectTransform _root;
|
||
private Text _gold;
|
||
private Text _dust;
|
||
private Text _tokens;
|
||
private Text _status;
|
||
private bool _disposed;
|
||
private bool _refreshing;
|
||
|
||
public LobbyView(
|
||
Transform parent,
|
||
AppConfig config,
|
||
AuthService auth,
|
||
PlayerState player,
|
||
Action onLoggedOut,
|
||
Action onBattle,
|
||
Action onDecks,
|
||
Action onStore,
|
||
Action onHistory,
|
||
Action onRating,
|
||
Action onCommunity)
|
||
{
|
||
_auth = auth;
|
||
_player = player;
|
||
_onLoggedOut = onLoggedOut;
|
||
_onStore = onStore;
|
||
|
||
_root = UiKit.CreatePanel(parent, RootName, new Color(0f, 0f, 0f, 0f));
|
||
_root.GetComponent<Image>().raycastTarget = false;
|
||
|
||
_topBar = new PlayerTopBar(
|
||
_root,
|
||
config,
|
||
player,
|
||
onLoggedOut,
|
||
onHistory,
|
||
onRating,
|
||
onCommunity,
|
||
overlayParent: _root);
|
||
|
||
BuildActions(onBattle, onDecks, onStore);
|
||
BuildMissions(out _status);
|
||
BuildBalances(out _gold, out _dust, out _tokens);
|
||
BuildChat();
|
||
BuildFriends();
|
||
|
||
_ticker = _root.gameObject.AddComponent<StatusTicker>();
|
||
_ticker.Hide = () => SetStatus(string.Empty);
|
||
|
||
_player.Changed += UpdateTexts;
|
||
Loc.LanguageChanged += UpdateTexts;
|
||
UpdateTexts();
|
||
_root.gameObject.SetActive(false);
|
||
}
|
||
|
||
public bool IsMenuOpen => _topBar != null && _topBar.IsMenuOpen;
|
||
|
||
public void CloseMenu()
|
||
{
|
||
if (_topBar != null)
|
||
_topBar.CloseMenu();
|
||
}
|
||
|
||
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;
|
||
Loc.LanguageChanged -= UpdateTexts;
|
||
_topBar?.Dispose();
|
||
}
|
||
|
||
// ------------------------------------------------------------ левая колонка
|
||
|
||
private void BuildActions(Action onBattle, Action onDecks, Action onStore)
|
||
{
|
||
var actions = NewRect(_root, "Actions");
|
||
actions.anchorMin = new Vector2(0f, 1f);
|
||
actions.anchorMax = new Vector2(0f, 1f);
|
||
actions.pivot = new Vector2(0f, 1f);
|
||
actions.sizeDelta = new Vector2(LeftWidth, 428f);
|
||
actions.anchoredPosition = new Vector2(Margin, -ContentTop);
|
||
|
||
ActionCard(
|
||
actions,
|
||
"BattleCard",
|
||
"BATTLE",
|
||
"Найдите соперника и сразитесь",
|
||
LobbyIcon.Swords,
|
||
0f,
|
||
true,
|
||
onBattle);
|
||
|
||
ActionCard(
|
||
actions,
|
||
"DecksCard",
|
||
"DECK BUILDER",
|
||
"Соберите и настройте колоду",
|
||
LobbyIcon.Deck,
|
||
-148f,
|
||
false,
|
||
onDecks);
|
||
|
||
ActionCard(
|
||
actions,
|
||
"ShopCard",
|
||
"SHOP",
|
||
"Бустеры, триал-деки и токены",
|
||
LobbyIcon.Shop,
|
||
-296f,
|
||
false,
|
||
onStore);
|
||
}
|
||
|
||
private static void ActionCard(
|
||
RectTransform parent,
|
||
string name,
|
||
string title,
|
||
string subtitle,
|
||
Action<RectTransform, Color> icon,
|
||
float y,
|
||
bool primary,
|
||
Action onClick)
|
||
{
|
||
var card = Surface(
|
||
parent,
|
||
name,
|
||
PanelFill,
|
||
primary ? BorderStrong : Border,
|
||
primary ? 2 : 1,
|
||
18);
|
||
card.anchorMin = new Vector2(0f, 1f);
|
||
card.anchorMax = new Vector2(0f, 1f);
|
||
card.pivot = new Vector2(0f, 1f);
|
||
card.sizeDelta = new Vector2(LeftWidth, 132f);
|
||
card.anchoredPosition = new Vector2(0f, y);
|
||
|
||
var image = card.GetComponent<Image>();
|
||
image.raycastTarget = true;
|
||
var button = card.gameObject.AddComponent<Button>();
|
||
button.targetGraphic = image;
|
||
button.transition = Selectable.Transition.ColorTint;
|
||
button.colors = HoverColors();
|
||
button.onClick.AddListener(() => onClick());
|
||
|
||
var iconRect = Icon(card, new Vector2(64f, 64f), new Vector2(-LeftWidth * 0.5f + 56f, 0f), 1f);
|
||
icon(iconRect, primary ? BorderStrong : Accent);
|
||
|
||
var titleText = UiKit.CreateText(
|
||
card,
|
||
"Title",
|
||
title,
|
||
27,
|
||
TextPrimary,
|
||
TextAnchor.MiddleLeft);
|
||
titleText.fontStyle = FontStyle.Bold;
|
||
var titleRect = titleText.rectTransform;
|
||
titleRect.anchorMin = new Vector2(0f, 1f);
|
||
titleRect.anchorMax = new Vector2(0f, 1f);
|
||
titleRect.pivot = new Vector2(0f, 1f);
|
||
titleRect.sizeDelta = new Vector2(380f, 34f);
|
||
titleRect.anchoredPosition = new Vector2(104f, -30f);
|
||
|
||
var subtitleText = UiKit.CreateText(
|
||
card,
|
||
"Subtitle",
|
||
subtitle,
|
||
15,
|
||
TextMuted,
|
||
TextAnchor.MiddleLeft);
|
||
var subtitleRect = subtitleText.rectTransform;
|
||
subtitleRect.anchorMin = new Vector2(0f, 1f);
|
||
subtitleRect.anchorMax = new Vector2(0f, 1f);
|
||
subtitleRect.pivot = new Vector2(0f, 1f);
|
||
subtitleRect.sizeDelta = new Vector2(420f, 24f);
|
||
subtitleRect.anchoredPosition = new Vector2(104f, -72f);
|
||
|
||
var chevron = Icon(card, new Vector2(18f, 18f), new Vector2(LeftWidth * 0.5f - 34f, 0f), 0.35f);
|
||
LobbyIcon.Chevron(chevron, TextMuted);
|
||
}
|
||
|
||
// ------------------------------------------------------------ миссии
|
||
|
||
private void BuildMissions(out Text status)
|
||
{
|
||
var panel = Surface(_root, "MissionsPanel", PanelFill, Border, 1, 16);
|
||
panel.anchorMin = new Vector2(0f, 1f);
|
||
panel.anchorMax = new Vector2(0f, 1f);
|
||
panel.pivot = new Vector2(0f, 1f);
|
||
panel.sizeDelta = new Vector2(LeftWidth, 396f);
|
||
panel.anchoredPosition = new Vector2(Margin, -(ContentTop + 428f + Gutter));
|
||
|
||
var iconRect = Icon(panel, new Vector2(28f, 28f), new Vector2(-LeftWidth * 0.5f + 30f, 182f), 0.5f);
|
||
LobbyIcon.Shield(iconRect, Accent);
|
||
|
||
var title = UiKit.CreateText(
|
||
panel,
|
||
"Title",
|
||
"Ежедневные / еженедельные задания",
|
||
17,
|
||
TextPrimary,
|
||
TextAnchor.MiddleLeft);
|
||
title.fontStyle = FontStyle.Bold;
|
||
var titleRect = title.rectTransform;
|
||
titleRect.anchorMin = new Vector2(0f, 1f);
|
||
titleRect.anchorMax = new Vector2(0f, 1f);
|
||
titleRect.pivot = new Vector2(0f, 1f);
|
||
titleRect.sizeDelta = new Vector2(380f, 28f);
|
||
titleRect.anchoredPosition = new Vector2(50f, -20f);
|
||
|
||
StubUi.Badge(panel, new Vector2(-16f, -16f));
|
||
|
||
for (var i = 0; i < 3; i++)
|
||
{
|
||
var row = Surface(
|
||
panel,
|
||
"MissionRow" + i,
|
||
PanelFillSoft,
|
||
new Color(0.16f, 0.42f, 0.85f, 0.3f),
|
||
1,
|
||
10);
|
||
row.anchorMin = new Vector2(0.5f, 1f);
|
||
row.anchorMax = new Vector2(0.5f, 1f);
|
||
row.pivot = new Vector2(0.5f, 1f);
|
||
row.sizeDelta = new Vector2(528f, 88f);
|
||
row.anchoredPosition = new Vector2(0f, -62f - i * 96f);
|
||
|
||
var lockRect = Icon(row, new Vector2(34f, 34f), new Vector2(-264f + 32f, 0f), 0.6f);
|
||
LobbyIcon.Lock(lockRect, TextDim);
|
||
|
||
var rowTitle = UiKit.CreateText(
|
||
row,
|
||
"Title",
|
||
"Задание появится позже",
|
||
15,
|
||
TextMuted,
|
||
TextAnchor.MiddleLeft);
|
||
var rowTitleRect = rowTitle.rectTransform;
|
||
rowTitleRect.anchorMin = new Vector2(0f, 0.5f);
|
||
rowTitleRect.anchorMax = new Vector2(1f, 0.5f);
|
||
rowTitleRect.offsetMin = new Vector2(64f, 8f);
|
||
rowTitleRect.offsetMax = new Vector2(-20f, 26f);
|
||
|
||
var rowNote = UiKit.CreateText(
|
||
row,
|
||
"Note",
|
||
"Награды и прогресс — после появления серверных заданий.",
|
||
12,
|
||
TextDim,
|
||
TextAnchor.MiddleLeft);
|
||
var rowNoteRect = rowNote.rectTransform;
|
||
rowNoteRect.anchorMin = new Vector2(0f, 0.5f);
|
||
rowNoteRect.anchorMax = new Vector2(1f, 0.5f);
|
||
rowNoteRect.offsetMin = new Vector2(64f, -30f);
|
||
rowNoteRect.offsetMax = new Vector2(-20f, -8f);
|
||
}
|
||
|
||
status = UiKit.CreateText(
|
||
_root,
|
||
"LobbyStatus",
|
||
string.Empty,
|
||
14,
|
||
new Color(1f, 0.62f, 0.5f),
|
||
TextAnchor.MiddleCenter);
|
||
var statusRect = status.rectTransform;
|
||
statusRect.anchorMin = new Vector2(0.5f, 0f);
|
||
statusRect.anchorMax = new Vector2(0.5f, 0f);
|
||
statusRect.pivot = new Vector2(0.5f, 0f);
|
||
statusRect.sizeDelta = new Vector2(900f, 20f);
|
||
statusRect.anchoredPosition = new Vector2(0f, 2f);
|
||
}
|
||
|
||
// ------------------------------------------------------------ балансы
|
||
|
||
private void BuildBalances(out Text gold, out Text dust, out Text tokens)
|
||
{
|
||
var panel = Surface(
|
||
_root,
|
||
"Balances",
|
||
new Color(0.02f, 0.05f, 0.13f, 0.94f),
|
||
Border,
|
||
1,
|
||
14);
|
||
panel.anchorMin = new Vector2(0f, 0f);
|
||
panel.anchorMax = new Vector2(0f, 0f);
|
||
panel.pivot = new Vector2(0f, 0f);
|
||
panel.sizeDelta = new Vector2(LeftWidth, BalanceHeight);
|
||
panel.anchoredPosition = new Vector2(Margin, BottomMargin);
|
||
|
||
var image = panel.GetComponent<Image>();
|
||
image.raycastTarget = true;
|
||
var button = panel.gameObject.AddComponent<Button>();
|
||
button.targetGraphic = image;
|
||
button.transition = Selectable.Transition.ColorTint;
|
||
button.colors = HoverColors();
|
||
button.onClick.AddListener(() => _onStore());
|
||
|
||
gold = BalanceGroup(panel, "Gold", "Золото", -LeftWidth / 3f, new Color(1f, 0.78f, 0.32f), 0);
|
||
dust = BalanceGroup(panel, "Dust", "Пыль", 0f, new Color(0.44f, 0.78f, 1f), 1);
|
||
tokens = BalanceGroup(panel, "Tokens", "Токены", LeftWidth / 3f, new Color(0.72f, 0.52f, 1f), 2);
|
||
}
|
||
|
||
private static Text BalanceGroup(
|
||
RectTransform parent,
|
||
string name,
|
||
string caption,
|
||
float x,
|
||
Color color,
|
||
int kind)
|
||
{
|
||
var group = NewRect(parent, name);
|
||
group.anchorMin = new Vector2(0.5f, 0.5f);
|
||
group.anchorMax = new Vector2(0.5f, 0.5f);
|
||
group.pivot = new Vector2(0.5f, 0.5f);
|
||
group.sizeDelta = new Vector2(176f, 64f);
|
||
group.anchoredPosition = new Vector2(x, 0f);
|
||
|
||
if (kind == 0)
|
||
{
|
||
NeonUi.AddImage(group, "Icon", NeonUi.Circle(22, color), new Vector2(22f, 22f), new Vector2(-64f, 10f));
|
||
}
|
||
else if (kind == 1)
|
||
{
|
||
var diamond = NeonUi.AddImage(
|
||
group,
|
||
"Icon",
|
||
NeonUi.Body(16, 16, 3, color, color, 1),
|
||
new Vector2(16f, 16f),
|
||
new Vector2(-64f, 10f));
|
||
diamond.rectTransform.localRotation = Quaternion.Euler(0f, 0f, 45f);
|
||
}
|
||
else
|
||
{
|
||
NeonUi.AddImage(group, "Icon", NeonUi.Ring(20, 3f, color), new Vector2(20f, 20f), new Vector2(-64f, 10f));
|
||
}
|
||
|
||
var value = UiKit.CreateText(group, "Value", "0", 22, TextPrimary);
|
||
value.fontStyle = FontStyle.Bold;
|
||
var valueRect = value.rectTransform;
|
||
valueRect.anchorMin = new Vector2(0f, 0.5f);
|
||
valueRect.anchorMax = new Vector2(0f, 0.5f);
|
||
valueRect.pivot = new Vector2(0f, 0.5f);
|
||
valueRect.sizeDelta = new Vector2(120f, 28f);
|
||
valueRect.anchoredPosition = new Vector2(-46f, 10f);
|
||
UiKit.MakeLiteral(value);
|
||
|
||
var label = UiKit.CreateText(
|
||
group,
|
||
"Caption",
|
||
caption,
|
||
12,
|
||
TextDim,
|
||
TextAnchor.MiddleLeft);
|
||
var labelRect = label.rectTransform;
|
||
labelRect.anchorMin = new Vector2(0f, 0.5f);
|
||
labelRect.anchorMax = new Vector2(0f, 0.5f);
|
||
labelRect.pivot = new Vector2(0f, 0.5f);
|
||
labelRect.sizeDelta = new Vector2(140f, 18f);
|
||
labelRect.anchoredPosition = new Vector2(-46f, -12f);
|
||
|
||
return value;
|
||
}
|
||
|
||
// ------------------------------------------------------------ чат и друзья
|
||
|
||
private void BuildChat()
|
||
{
|
||
var panel = Surface(
|
||
_root,
|
||
"ChatPanel",
|
||
new Color(0.018f, 0.045f, 0.12f, 0.9f),
|
||
Border,
|
||
1,
|
||
16);
|
||
panel.anchorMin = new Vector2(600f / 1920f, 0f);
|
||
panel.anchorMax = new Vector2(1560f / 1920f, 1f);
|
||
panel.offsetMin = new Vector2(0f, BottomMargin);
|
||
panel.offsetMax = new Vector2(0f, -ContentTop);
|
||
|
||
var headerIcon = Icon(panel, new Vector2(28f, 28f), new Vector2(-450f, 440f), 0.5f);
|
||
LobbyIcon.Chat(headerIcon, Accent);
|
||
|
||
var header = UiKit.CreateText(
|
||
panel,
|
||
"Title",
|
||
"Чат",
|
||
20,
|
||
TextPrimary,
|
||
TextAnchor.MiddleLeft);
|
||
header.fontStyle = FontStyle.Bold;
|
||
var headerRect = header.rectTransform;
|
||
headerRect.anchorMin = new Vector2(0f, 1f);
|
||
headerRect.anchorMax = new Vector2(0f, 1f);
|
||
headerRect.pivot = new Vector2(0f, 1f);
|
||
headerRect.sizeDelta = new Vector2(240f, 30f);
|
||
headerRect.anchoredPosition = new Vector2(56f, -16f);
|
||
|
||
StubUi.Badge(panel, new Vector2(-16f, -14f));
|
||
|
||
StubUi.Panel(
|
||
panel,
|
||
"ChatStub",
|
||
"Чат появится позже",
|
||
"Здесь будет общий чат лобби и личные сообщения. Пока серверного канала нет.");
|
||
|
||
var input = Surface(
|
||
panel,
|
||
"ChatInput",
|
||
new Color(0.01f, 0.03f, 0.08f, 0.9f),
|
||
new Color(0.16f, 0.42f, 0.85f, 0.35f),
|
||
1,
|
||
10);
|
||
input.anchorMin = new Vector2(0f, 0f);
|
||
input.anchorMax = new Vector2(1f, 0f);
|
||
input.pivot = new Vector2(0.5f, 0f);
|
||
input.offsetMin = new Vector2(18f, 18f);
|
||
input.offsetMax = new Vector2(-80f, 70f);
|
||
|
||
var placeholder = UiKit.CreateText(
|
||
input,
|
||
"Placeholder",
|
||
"Введите сообщение…",
|
||
16,
|
||
TextDim,
|
||
TextAnchor.MiddleLeft);
|
||
UiKit.Stretch(placeholder.rectTransform);
|
||
placeholder.rectTransform.offsetMin = new Vector2(18f, 0f);
|
||
placeholder.rectTransform.offsetMax = new Vector2(-18f, 0f);
|
||
|
||
var send = Surface(
|
||
panel,
|
||
"ChatSend",
|
||
new Color(0.06f, 0.16f, 0.36f, 0.7f),
|
||
new Color(0.16f, 0.42f, 0.85f, 0.35f),
|
||
1,
|
||
10);
|
||
send.anchorMin = new Vector2(1f, 0f);
|
||
send.anchorMax = new Vector2(1f, 0f);
|
||
send.pivot = new Vector2(1f, 0f);
|
||
send.sizeDelta = new Vector2(48f, 52f);
|
||
send.anchoredPosition = new Vector2(-18f, 18f);
|
||
var chevron = Icon(send, new Vector2(18f, 18f), Vector2.zero, 0.35f);
|
||
LobbyIcon.Chevron(chevron, TextDim);
|
||
}
|
||
|
||
private void BuildFriends()
|
||
{
|
||
var panel = Surface(
|
||
_root,
|
||
"FriendsPanel",
|
||
new Color(0.018f, 0.045f, 0.12f, 0.9f),
|
||
Border,
|
||
1,
|
||
16);
|
||
panel.anchorMin = new Vector2(1560f / 1920f, 0f);
|
||
panel.anchorMax = new Vector2(1896f / 1920f, 1f);
|
||
panel.offsetMin = new Vector2(0f, BottomMargin);
|
||
panel.offsetMax = new Vector2(0f, -ContentTop);
|
||
|
||
var iconRect = Icon(panel, new Vector2(28f, 28f), new Vector2(-RightWidth * 0.5f + 30f, 440f), 0.5f);
|
||
LobbyIcon.Friends(iconRect, Accent);
|
||
|
||
var header = UiKit.CreateText(
|
||
panel,
|
||
"Title",
|
||
"Друзья онлайн",
|
||
17,
|
||
TextPrimary,
|
||
TextAnchor.MiddleLeft);
|
||
header.fontStyle = FontStyle.Bold;
|
||
var headerRect = header.rectTransform;
|
||
headerRect.anchorMin = new Vector2(0f, 1f);
|
||
headerRect.anchorMax = new Vector2(0f, 1f);
|
||
headerRect.pivot = new Vector2(0f, 1f);
|
||
headerRect.sizeDelta = new Vector2(240f, 28f);
|
||
headerRect.anchoredPosition = new Vector2(52f, -16f);
|
||
|
||
StubUi.Badge(panel, new Vector2(-14f, -14f));
|
||
|
||
for (var i = 0; i < 5; i++)
|
||
{
|
||
var row = Surface(
|
||
panel,
|
||
"FriendRow" + i,
|
||
PanelFillSoft,
|
||
new Color(0.16f, 0.42f, 0.85f, 0.22f),
|
||
1,
|
||
10);
|
||
row.anchorMin = new Vector2(0.5f, 1f);
|
||
row.anchorMax = new Vector2(0.5f, 1f);
|
||
row.pivot = new Vector2(0.5f, 1f);
|
||
row.sizeDelta = new Vector2(RightWidth - 24f, 62f);
|
||
row.anchoredPosition = new Vector2(0f, -62f - i * 72f);
|
||
|
||
var avatarRect = Surface(
|
||
row,
|
||
"Avatar",
|
||
new Color(0.06f, 0.14f, 0.3f, 0.9f),
|
||
new Color(0.2f, 0.45f, 0.85f, 0.4f),
|
||
1,
|
||
16);
|
||
avatarRect.anchorMin = new Vector2(0f, 0.5f);
|
||
avatarRect.anchorMax = new Vector2(0f, 0.5f);
|
||
avatarRect.pivot = new Vector2(0f, 0.5f);
|
||
avatarRect.sizeDelta = new Vector2(36f, 36f);
|
||
avatarRect.anchoredPosition = new Vector2(12f, 0f);
|
||
|
||
var name = UiKit.CreateText(
|
||
row,
|
||
"Name",
|
||
"—",
|
||
14,
|
||
TextMuted,
|
||
TextAnchor.MiddleLeft);
|
||
var nameRect = name.rectTransform;
|
||
nameRect.anchorMin = new Vector2(0f, 0.5f);
|
||
nameRect.anchorMax = new Vector2(1f, 0.5f);
|
||
nameRect.offsetMin = new Vector2(58f, 4f);
|
||
nameRect.offsetMax = new Vector2(-12f, 24f);
|
||
|
||
var state = UiKit.CreateText(
|
||
row,
|
||
"State",
|
||
"скоро",
|
||
12,
|
||
TextDim,
|
||
TextAnchor.MiddleLeft);
|
||
var stateRect = state.rectTransform;
|
||
stateRect.anchorMin = new Vector2(0f, 0.5f);
|
||
stateRect.anchorMax = new Vector2(1f, 0.5f);
|
||
stateRect.offsetMin = new Vector2(58f, -26f);
|
||
stateRect.offsetMax = new Vector2(-12f, -6f);
|
||
}
|
||
|
||
var note = UiKit.CreateText(
|
||
panel,
|
||
"Note",
|
||
"Список друзей появится вместе с сервером.",
|
||
12,
|
||
TextDim,
|
||
TextAnchor.LowerCenter);
|
||
var noteRect = note.rectTransform;
|
||
noteRect.anchorMin = new Vector2(0f, 0f);
|
||
noteRect.anchorMax = new Vector2(1f, 0f);
|
||
noteRect.pivot = new Vector2(0.5f, 0f);
|
||
noteRect.offsetMin = new Vector2(12f, 16f);
|
||
noteRect.offsetMax = new Vector2(-12f, 16f);
|
||
noteRect.sizeDelta = new Vector2(noteRect.sizeDelta.x, 32f);
|
||
}
|
||
|
||
// ------------------------------------------------------------ состояние
|
||
|
||
private async Task RefreshAsync()
|
||
{
|
||
if (_refreshing || _disposed)
|
||
return;
|
||
|
||
_refreshing = true;
|
||
try
|
||
{
|
||
await _auth.RefreshMeAsync();
|
||
if (!_disposed)
|
||
SetStatus(string.Empty);
|
||
}
|
||
catch (ApiException exception) when (exception.StatusCode == 401)
|
||
{
|
||
if (!_disposed)
|
||
_onLoggedOut();
|
||
}
|
||
catch (Exception exception)
|
||
{
|
||
Debug.LogException(exception);
|
||
if (!_disposed)
|
||
SetStatus("Не удалось обновить профиль. Сервер недоступен?");
|
||
}
|
||
finally
|
||
{
|
||
_refreshing = false;
|
||
}
|
||
}
|
||
|
||
private void UpdateTexts()
|
||
{
|
||
if (_disposed)
|
||
return;
|
||
|
||
_gold.text = _player.Gold.ToString();
|
||
_dust.text = _player.Dust.ToString();
|
||
_tokens.text = _player.Tokens.ToString();
|
||
}
|
||
|
||
private void SetStatus(string text)
|
||
{
|
||
if (_status == null)
|
||
return;
|
||
|
||
_status.text = text ?? string.Empty;
|
||
_ticker.HideAt = string.IsNullOrEmpty(text) ? 0f : Time.unscaledTime + 6f;
|
||
}
|
||
|
||
// ------------------------------------------------------------ утилиты
|
||
|
||
private static RectTransform NewRect(Transform parent, string name)
|
||
{
|
||
var go = new GameObject(name, typeof(RectTransform));
|
||
var rect = (RectTransform)go.transform;
|
||
rect.SetParent(parent, false);
|
||
return rect;
|
||
}
|
||
|
||
private static RectTransform Surface(
|
||
Transform parent,
|
||
string name,
|
||
Color fill,
|
||
Color border,
|
||
int borderWidth,
|
||
int radius)
|
||
{
|
||
var go = new GameObject(name, typeof(RectTransform), typeof(Image));
|
||
var rect = (RectTransform)go.transform;
|
||
rect.SetParent(parent, false);
|
||
|
||
var image = go.GetComponent<Image>();
|
||
image.sprite = radius > 0
|
||
? NeonUi.BodySliced(radius, fill, border, borderWidth)
|
||
: NeonUi.BodySliced(0, fill, border, borderWidth);
|
||
image.type = Image.Type.Sliced;
|
||
image.color = Color.white;
|
||
image.raycastTarget = false;
|
||
return rect;
|
||
}
|
||
|
||
private static RectTransform Icon(
|
||
Transform parent,
|
||
Vector2 size,
|
||
Vector2 position,
|
||
float scale)
|
||
{
|
||
var rect = NewRect(parent, "Icon");
|
||
rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||
rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||
rect.pivot = new Vector2(0.5f, 0.5f);
|
||
rect.sizeDelta = size;
|
||
rect.anchoredPosition = position;
|
||
rect.localScale = Vector3.one * scale;
|
||
return rect;
|
||
}
|
||
|
||
private static ColorBlock HoverColors()
|
||
{
|
||
return new ColorBlock
|
||
{
|
||
normalColor = Color.white,
|
||
highlightedColor = new Color(1.16f, 1.16f, 1.16f, 1f),
|
||
pressedColor = new Color(0.9f, 0.9f, 0.9f, 1f),
|
||
selectedColor = Color.white,
|
||
disabledColor = new Color(0.55f, 0.55f, 0.55f, 0.6f),
|
||
colorMultiplier = 1f,
|
||
fadeDuration = 0.08f,
|
||
};
|
||
}
|
||
|
||
/// <summary>Скрывает статус через несколько секунд.</summary>
|
||
private sealed class StatusTicker : MonoBehaviour
|
||
{
|
||
public float HideAt;
|
||
public Action Hide;
|
||
|
||
private void Update()
|
||
{
|
||
if (HideAt <= 0f || Time.unscaledTime < HideAt)
|
||
return;
|
||
|
||
HideAt = 0f;
|
||
Hide?.Invoke();
|
||
}
|
||
}
|
||
}
|
||
}
|