using System;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.App;
using Vanguard.Auth;
namespace Vanguard.UI
{
/// Экран входа по референсу: key art, неоновая панель, меню.
public sealed class LoginView
{
private const int PanelWidth = 560;
private const int PanelHeight = 420;
private readonly AppConfig _config;
private readonly AuthService _auth;
private readonly Action _onAuthenticated;
private readonly RectTransform _root;
private readonly InputField _userName;
private readonly InputField _password;
private readonly Image _passwordToggle;
private readonly Button _loginButton;
private readonly Text _loginLabel;
private readonly Button _registerButton;
private readonly Text _status;
private readonly StatusTicker _ticker;
private readonly HamburgerMenu _menu;
private bool _busy;
private bool _passwordVisible;
public LoginView(
Transform parent,
AppConfig config,
AuthService auth,
Action onAuthenticated)
{
_config = config;
_auth = auth;
_onAuthenticated = onAuthenticated;
_root = UiKit.CreatePanel(parent, "LoginScreen", new Color(0f, 0f, 0f, 0f));
_root.GetComponent().raycastTarget = false;
LoginBackdrop.Create(_root);
var panel = CreatePanel(_root);
_userName = CreateField(panel, "UserName", "Логин", UserIcon(), 110f);
_password = CreateField(panel, "Password", "Пароль", LockIcon(), 32f, password: true);
_passwordToggle = CreatePasswordToggle(panel);
var tabs = _root.gameObject.AddComponent();
tabs.First = _userName;
tabs.Second = _password;
tabs.Submit = OnSubmitShortcut;
tabs.Cancel = OnCancelShortcut;
CreateLink(
panel,
"ForgotPassword",
"Забыли пароль?",
-14f,
TextAnchor.MiddleRight,
new Color(0.37f, 0.69f, 1f),
OnForgotClicked);
_loginButton = CreateLoginButton(panel, out _loginLabel);
_registerButton = CreateLink(
panel,
"Register",
"Создать аккаунт",
-128f,
TextAnchor.MiddleCenter,
new Color(0.50f, 0.66f, 0.88f),
OnRegisterClicked);
_status = UiKit.CreateText(
panel,
"Status",
string.Empty,
15,
new Color(0.62f, 0.72f, 0.88f),
TextAnchor.UpperCenter);
_status.horizontalOverflow = HorizontalWrapMode.Wrap;
_status.verticalOverflow = VerticalWrapMode.Overflow;
Place(_status.rectTransform, new Vector2(500f, 44f), new Vector2(0f, -172f));
CreateTagline(_root);
CreateCopyright(_root);
_ticker = _root.gameObject.AddComponent();
_ticker.Hide = () => SetStatus(string.Empty, StatusColor);
_menu = new HamburgerMenu(_root, _config);
}
/// Enter отправляет форму; в открытом меню не срабатывает.
private void OnSubmitShortcut()
{
if (_busy || _menu == null || _menu.IsOpen)
return;
_ = SubmitAsync(register: false);
}
/// Esc закрывает меню, если оно открыто.
private void OnCancelShortcut()
{
if (_menu != null && _menu.IsOpen)
_menu.Close();
}
public void Show(string status = null)
{
UiKit.SetActive(_root, true);
if (!string.IsNullOrEmpty(status))
SetStatus(status, StatusColor);
}
public void Hide() => UiKit.SetActive(_root, false);
// ------------------------------------------------------------ построение
private static RectTransform CreatePanel(Transform parent)
{
var glow = NeonUi.AddImage(
parent,
"PanelGlow",
NeonUi.Glow(
PanelWidth + 48,
PanelHeight + 48,
24,
24,
new Color(0.18f, 0.49f, 1f, 0.24f)),
new Vector2(PanelWidth + 48, PanelHeight + 48),
new Vector2(0f, -170f));
var panel = UiKit.CreateCenteredCard(
parent,
"LoginPanel",
new Vector2(PanelWidth, PanelHeight),
Color.white);
panel.anchoredPosition = new Vector2(0f, -170f);
panel.GetComponent().sprite = NeonUi.Body(
PanelWidth,
PanelHeight,
24,
new Color(0.024f, 0.058f, 0.15f, 0.94f),
new Color(0.18f, 0.49f, 1f, 0.9f),
2);
panel.GetComponent().raycastTarget = false;
glow.transform.SetSiblingIndex(panel.GetSiblingIndex() - 1);
return panel;
}
private static InputField CreateField(
Transform parent,
string name,
string placeholder,
Sprite icon,
float y,
bool password = false)
{
var go = new GameObject(name, typeof(RectTransform), typeof(Image), typeof(InputField));
var rect = (RectTransform)go.transform;
rect.SetParent(parent, false);
Place(rect, new Vector2(480f, 64f), new Vector2(0f, y));
var background = go.GetComponent();
background.sprite = NeonUi.Body(
480,
64,
10,
new Color(0.014f, 0.041f, 0.105f, 0.97f),
new Color(0.22f, 0.53f, 1f, 0.55f),
1);
background.type = Image.Type.Simple;
background.raycastTarget = true;
var input = go.GetComponent();
input.targetGraphic = background;
input.lineType = InputField.LineType.SingleLine;
input.contentType = password
? InputField.ContentType.Password
: InputField.ContentType.Standard;
input.characterLimit = password ? 128 : 64;
input.caretColor = new Color(0.55f, 0.82f, 1f);
input.customCaretColor = true;
input.selectionColor = new Color(0.22f, 0.53f, 1f, 0.55f);
input.colors = FieldColors();
var text = UiKit.CreateText(rect, "Text", string.Empty, 18, Color.white, TextAnchor.MiddleLeft);
UiKit.Stretch(text.rectTransform);
text.rectTransform.offsetMin = new Vector2(52f, 0f);
text.rectTransform.offsetMax = new Vector2(-44f, 0f);
text.supportRichText = false;
UiKit.MakeLiteral(text);
var hint = UiKit.CreateText(
rect,
"Placeholder",
placeholder,
18,
new Color(0.55f, 0.63f, 0.78f),
TextAnchor.MiddleLeft);
UiKit.Stretch(hint.rectTransform);
hint.rectTransform.offsetMin = new Vector2(52f, 0f);
hint.rectTransform.offsetMax = new Vector2(-44f, 0f);
hint.supportRichText = false;
input.textComponent = text;
input.placeholder = hint;
NeonUi.AddImage(rect, "Icon", icon, new Vector2(22f, 22f), new Vector2(-212f, 0f));
return input;
}
private Image CreatePasswordToggle(Transform parent)
{
var go = new GameObject(
"PasswordToggle",
typeof(RectTransform),
typeof(Image),
typeof(Button));
var rect = (RectTransform)go.transform;
rect.SetParent(parent, false);
Place(rect, new Vector2(32f, 32f), new Vector2(208f, 32f));
var image = go.GetComponent();
image.sprite = EyeIcon();
image.color = new Color(1f, 1f, 1f, 0.75f);
image.raycastTarget = true;
var button = go.GetComponent