Files
XRLib/Assets/Scripts/UVC/UIToolkit/Modal/UTKAlert.cs

333 lines
10 KiB
C#
Raw Normal View History

2026-01-08 20:15:57 +09:00
#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
using UVC.UIToolkit.Modal;
namespace UVC.UIToolkit
{
/// <summary>
/// Alert 팝업 컴포넌트.
/// 사용자에게 중요한 정보를 알립니다.
/// </summary>
[UxmlElement]
public partial class UTKAlert : VisualElement, IDisposable
{
#region Constants
private const string USS_PATH = "UIToolkit/Modal/UTKAlert";
#endregion
#region Fields
private bool _disposed;
private UTKModalBlocker? _blocker;
private VisualElement? _iconContainer;
private Label? _iconLabel;
private Label? _titleLabel;
private Label? _messageLabel;
private VisualElement? _buttonContainer;
private string _title = "";
private string _message = "";
private AlertType _alertType = AlertType.Info;
#endregion
#region Events
/// <summary>닫힘 이벤트</summary>
public event Action? OnClosed;
/// <summary>확인 이벤트</summary>
public event Action? OnConfirm;
/// <summary>취소 이벤트</summary>
public event Action? OnCancel;
#endregion
#region Properties
/// <summary>제목</summary>
[UxmlAttribute]
public string Title
{
get => _title;
set
{
_title = value;
if (_titleLabel != null)
{
_titleLabel.text = value;
_titleLabel.style.display = string.IsNullOrEmpty(value) ? DisplayStyle.None : DisplayStyle.Flex;
}
}
}
/// <summary>메시지</summary>
[UxmlAttribute]
public string Message
{
get => _message;
set
{
_message = value;
if (_messageLabel != null) _messageLabel.text = value;
}
}
/// <summary>알림 유형</summary>
[UxmlAttribute]
public AlertType Type
{
get => _alertType;
set
{
_alertType = value;
UpdateType();
}
}
#endregion
#region Enums
public enum AlertType
{
Info,
Success,
Warning,
Error,
Confirm
}
#endregion
#region Constructor
public UTKAlert()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load<StyleSheet>(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
CreateUI();
SubscribeToThemeChanges();
}
public UTKAlert(string title, string message, AlertType type = AlertType.Info) : this()
{
Title = title;
Message = message;
Type = type;
}
#endregion
#region Static Factory
/// <summary>
/// Info 알림 표시
/// </summary>
public static UTKAlert ShowInfo(VisualElement parent, string title, string message, Action? onClose = null)
{
return Show(parent, title, message, AlertType.Info, onClose);
}
/// <summary>
/// Success 알림 표시
/// </summary>
public static UTKAlert ShowSuccess(VisualElement parent, string title, string message, Action? onClose = null)
{
return Show(parent, title, message, AlertType.Success, onClose);
}
/// <summary>
/// Warning 알림 표시
/// </summary>
public static UTKAlert ShowWarning(VisualElement parent, string title, string message, Action? onClose = null)
{
return Show(parent, title, message, AlertType.Warning, onClose);
}
/// <summary>
/// Error 알림 표시
/// </summary>
public static UTKAlert ShowError(VisualElement parent, string title, string message, Action? onClose = null)
{
return Show(parent, title, message, AlertType.Error, onClose);
}
/// <summary>
/// Confirm 대화상자 표시
/// </summary>
public static UTKAlert ShowConfirm(VisualElement parent, string title, string message, Action? onConfirm, Action? onCancel = null)
{
var alert = Show(parent, title, message, AlertType.Confirm, null);
alert.OnConfirm = onConfirm;
alert.OnCancel = onCancel;
return alert;
}
/// <summary>
/// 알림 표시
/// </summary>
public static UTKAlert Show(VisualElement parent, string title, string message, AlertType type, Action? onClose)
{
var alert = new UTKAlert(title, message, type);
alert.OnClosed = onClose;
alert._blocker = UTKModalBlocker.Show(parent, 0.5f, true);
alert._blocker.OnBlockerClicked += alert.Close;
alert._blocker.Add(alert);
// 중앙 정렬
alert.style.position = Position.Absolute;
alert.style.left = Length.Percent(50);
alert.style.top = Length.Percent(50);
alert.style.translate = new Translate(Length.Percent(-50), Length.Percent(-50));
return alert;
}
#endregion
#region UI Creation
private void CreateUI()
{
AddToClassList("utk-alert");
_iconContainer = new VisualElement { name = "icon-container" };
_iconContainer.AddToClassList("utk-alert__icon-container");
Add(_iconContainer);
_iconLabel = new Label { name = "icon" };
_iconLabel.AddToClassList("utk-alert__icon");
_iconContainer.Add(_iconLabel);
var contentContainer = new VisualElement { name = "content" };
contentContainer.AddToClassList("utk-alert__content");
Add(contentContainer);
_titleLabel = new Label { name = "title" };
_titleLabel.AddToClassList("utk-alert__title");
contentContainer.Add(_titleLabel);
_messageLabel = new Label { name = "message" };
_messageLabel.AddToClassList("utk-alert__message");
contentContainer.Add(_messageLabel);
_buttonContainer = new VisualElement { name = "buttons" };
_buttonContainer.AddToClassList("utk-alert__buttons");
Add(_buttonContainer);
UpdateType();
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback<DetachFromPanelEvent>(_ =>
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
});
}
private void OnThemeChanged(UTKTheme theme)
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
#endregion
#region Methods
private void UpdateType()
{
RemoveFromClassList("utk-alert--info");
RemoveFromClassList("utk-alert--success");
RemoveFromClassList("utk-alert--warning");
RemoveFromClassList("utk-alert--error");
RemoveFromClassList("utk-alert--confirm");
var typeClass = _alertType switch
{
AlertType.Success => "utk-alert--success",
AlertType.Warning => "utk-alert--warning",
AlertType.Error => "utk-alert--error",
AlertType.Confirm => "utk-alert--confirm",
_ => "utk-alert--info"
};
AddToClassList(typeClass);
// 아이콘 업데이트
if (_iconLabel != null)
{
_iconLabel.text = _alertType switch
{
AlertType.Success => "✓",
AlertType.Warning => "⚠",
AlertType.Error => "✕",
AlertType.Confirm => "?",
_ => ""
};
}
// 버튼 업데이트
UpdateButtons();
}
private void UpdateButtons()
{
if (_buttonContainer == null) return;
_buttonContainer.Clear();
if (_alertType == AlertType.Confirm)
{
var cancelBtn = new UTKButton("Cancel", "", UTKButton.ButtonVariant.Normal);
cancelBtn.AddToClassList("utk-alert__btn");
cancelBtn.OnClicked += () =>
{
OnCancel?.Invoke();
Close();
};
_buttonContainer.Add(cancelBtn);
var confirmBtn = new UTKButton("OK", "", UTKButton.ButtonVariant.Primary);
confirmBtn.AddToClassList("utk-alert__btn");
confirmBtn.OnClicked += () =>
{
OnConfirm?.Invoke();
Close();
};
_buttonContainer.Add(confirmBtn);
}
else
{
var okBtn = new UTKButton("OK", "", UTKButton.ButtonVariant.Primary);
okBtn.AddToClassList("utk-alert__btn");
okBtn.OnClicked += Close;
_buttonContainer.Add(okBtn);
}
}
/// <summary>
/// 알림 닫기
/// </summary>
public void Close()
{
OnClosed?.Invoke();
if (_blocker != null)
{
_blocker.OnBlockerClicked -= Close;
_blocker.Hide();
}
_blocker = null;
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
_disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
OnClosed = null;
OnConfirm = null;
OnCancel = null;
_blocker = null;
}
#endregion
}
}