VanguardReMaster/client/Assets/Vanguard/Runtime/UI/LoginView.cs

265 lines
9.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using Vanguard.Api;
using Vanguard.App;
using Vanguard.Auth;
namespace Vanguard.UI
{
/// <summary>Экран входа/регистрации и выбора адреса сервера.</summary>
public sealed class LoginView
{
private readonly AppConfig _config;
private readonly AuthService _auth;
private readonly Action _onAuthenticated;
private readonly RectTransform _root;
private readonly InputField _serverUrl;
private readonly InputField _userName;
private readonly InputField _password;
private readonly Button _loginButton;
private readonly Button _registerButton;
private readonly Text _status;
private bool _busy;
public LoginView(
Transform parent,
AppConfig config,
AuthService auth,
Action onAuthenticated)
{
_config = config;
_auth = auth;
_onAuthenticated = onAuthenticated;
_root = UiKit.CreatePanel(parent, "LoginScreen", new Color(0.01f, 0.02f, 0.04f, 0.28f));
// Мягкое неоновое свечение за панелью; 3D-стол остаётся виден по краям.
UiKit.CreateCenteredCard(
_root,
"LoginGlow",
new Vector2(760f, 900f),
new Color(0.04f, 0.22f, 0.80f, 0.12f));
var card = UiKit.CreateCenteredCard(
_root,
"LoginCard",
new Vector2(620f, 820f),
new Color(0.018f, 0.032f, 0.065f, 0.92f));
var layout = UiKit.AddVerticalLayout(card, 32, 10);
layout.childAlignment = TextAnchor.MiddleCenter;
var eyebrow = UiKit.CreateText(
card, "Eyebrow", "VANGUARD // NETWORK", 13,
new Color(0.35f, 0.72f, 1f));
UiKit.SetPreferredHeight(eyebrow, 20f);
var title = UiKit.CreateText(
card, "Title", "VANGUARD", 56, new Color(0.88f, 0.94f, 1f));
title.fontStyle = FontStyle.Bold;
UiKit.SetPreferredHeight(title, 66f);
var subtitle = UiKit.CreateText(
card, "Subtitle", "RE:MASTER · СЕТЕВОЙ КЛИЕНТ", 18,
new Color(0.52f, 0.64f, 0.86f));
UiKit.SetPreferredHeight(subtitle, 30f);
var accent = UiKit.CreatePanel(card, "Accent", new Color(0.12f, 0.52f, 1f, 0.9f));
UiKit.SetPreferredHeight(accent, 3f);
AddCaption(card, "Сервер");
_serverUrl = UiKit.CreateInput(card, "ServerUrl", "http://192.168.31.158:18080");
_serverUrl.text = _config.ServerBaseUrl;
UiKit.SetPreferredHeight(_serverUrl, 54f);
AddCaption(card, "Имя игрока");
_userName = UiKit.CreateInput(card, "UserName", "3–32 символа");
UiKit.SetPreferredHeight(_userName, 54f);
AddCaption(card, "Пароль");
_password = UiKit.CreateInput(card, "Password", "8–128 символов", password: true);
UiKit.SetPreferredHeight(_password, 54f);
_loginButton = UiKit.CreateButton(card, "LoginButton", "ВОЙТИ", OnLoginClicked, 22);
TintButton(_loginButton, new Color(0.10f, 0.42f, 0.95f, 1f), Color.white);
UiKit.SetPreferredHeight(_loginButton, 56f);
_registerButton = UiKit.CreateButton(
card, "RegisterButton", "СОЗДАТЬ АККАУНТ", OnRegisterClicked, 19);
TintButton(
_registerButton,
new Color(0.05f, 0.10f, 0.18f, 0.95f),
new Color(0.48f, 0.76f, 1f));
UiKit.SetPreferredHeight(_registerButton, 48f);
_status = UiKit.CreateText(
card, "Status", string.Empty, 17,
new Color(0.66f, 0.74f, 0.90f),
TextAnchor.UpperCenter);
_status.horizontalOverflow = HorizontalWrapMode.Wrap;
UiKit.SetPreferredHeight(_status, 64f);
var footer = UiKit.CreateText(
card,
"Footer",
"v" + Application.version + " · стенд 192.168.31.158:18080 · localhost:5080",
14,
new Color(0.38f, 0.46f, 0.62f));
UiKit.SetPreferredHeight(footer, 24f);
var language = UiKit.CreateLanguageButton(_root, "Language");
var languageRect = language.GetComponent<RectTransform>();
languageRect.anchorMin = new Vector2(1f, 1f);
languageRect.anchorMax = new Vector2(1f, 1f);
languageRect.pivot = new Vector2(1f, 1f);
languageRect.anchoredPosition = new Vector2(-24f, -24f);
languageRect.sizeDelta = new Vector2(72f, 40f);
}
public void Show(string status = null)
{
UiKit.SetActive(_root, true);
if (!string.IsNullOrEmpty(status))
SetStatus(status, new Color(0.70f, 0.75f, 0.86f));
}
public void Hide() => UiKit.SetActive(_root, false);
private static void AddCaption(Transform parent, string text)
{
var caption = UiKit.CreateText(
parent,
"Caption_" + text,
text,
16,
new Color(0.55f, 0.65f, 0.82f),
TextAnchor.MiddleLeft);
UiKit.SetPreferredHeight(caption, 22f);
}
private static void TintButton(Button button, Color background, Color label)
{
var image = button.GetComponent<Image>();
if (image != null)
image.color = background;
var text = button.GetComponentInChildren<Text>();
if (text != null)
text.color = label;
}
private async void OnLoginClicked()
{
await SubmitAsync(register: false);
}
private async void OnRegisterClicked()
{
await SubmitAsync(register: true);
}
private async Task SubmitAsync(bool register)
{
if (_busy)
return;
var userName = (_userName.text ?? string.Empty).Trim();
var password = _password.text ?? string.Empty;
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
{
SetStatus("Введите имя игрока и пароль.", new Color(1f, 0.70f, 0.35f));
return;
}
_config.SetServerBaseUrl(_serverUrl.text);
_serverUrl.text = _config.ServerBaseUrl;
SetBusy(true, register ? "Создаём аккаунт…" : "Подключаемся…");
try
{
if (register)
await _auth.RegisterAsync(userName, password);
else
await _auth.LoginAsync(userName, password);
_password.text = string.Empty;
SetStatus("Готово.", new Color(0.45f, 0.85f, 0.55f));
_onAuthenticated();
}
catch (ApiException exception)
{
SetStatus(FormatError(exception), new Color(1f, 0.55f, 0.45f));
}
catch (Exception exception)
{
Debug.LogException(exception);
var detail = exception.Message ?? string.Empty;
if (detail.IndexOf("Insecure connection", StringComparison.OrdinalIgnoreCase) >= 0)
{
SetStatus(
"Unity блокирует HTTP. Player Settings → Allow downloads over HTTP = Always, затем перезапусти Unity.",
new Color(1f, 0.55f, 0.45f));
}
else
{
SetStatus(
"Не удалось связаться: " + detail,
new Color(1f, 0.55f, 0.45f));
}
}
finally
{
SetBusy(false, null);
}
}
private static string FormatError(ApiException exception)
{
if (exception.StatusCode == 0)
return "Нет связи с сервером. Проверьте адрес и запущен ли сервер.";
if (exception.Violations.Count > 0)
{
var details = string.Join("\n", exception.Violations.Take(3).Select(item => item.Message));
return exception.Message + "\n" + details;
}
return string.IsNullOrEmpty(exception.Message)
? "Сервер вернул ошибку " + exception.StatusCode + "."
: exception.Message;
}
private void SetBusy(bool busy, string status)
{
if (_loginButton == null || _registerButton == null || _serverUrl == null
|| _userName == null || _password == null)
return;
_busy = busy;
_loginButton.interactable = !busy;
_registerButton.interactable = !busy;
_serverUrl.interactable = !busy;
_userName.interactable = !busy;
_password.interactable = !busy;
if (status != null)
SetStatus(status, new Color(0.70f, 0.75f, 0.86f));
}
private void SetStatus(string text, Color color)
{
if (_status == null)
return;
_status.text = text ?? string.Empty;
_status.color = color;
}
}
}