using System; using System.Threading; using Cysharp.Threading.Tasks; using PrimeTween; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace BriarQueen.UI.Menus { public class ConfirmActionWindow : MonoBehaviour { [Header("Root")] [SerializeField] private GameObject _root; [SerializeField] private CanvasGroup _canvasGroup; [SerializeField] private RectTransform _panelTransform; [Header("Text")] [SerializeField] private TextMeshProUGUI _titleText; [SerializeField] private TextMeshProUGUI _messageText; [SerializeField] private TextMeshProUGUI _confirmLabel; [SerializeField] private TextMeshProUGUI _cancelLabel; [Header("Buttons")] [SerializeField] private Button _confirmButton; [SerializeField] private Button _cancelButton; [Header("Tween Settings")] [SerializeField] private TweenSettings _tweenSettings = new() { duration = 0.18f, ease = Ease.OutBack, useUnscaledTime = true }; [SerializeField] private float _hiddenScale = 0.92f; private Action _onCancel; private Action _onConfirm; private CancellationTokenSource _cts; private Sequence _sequence; public bool IsOpen { get; private set; } private void Awake() { ResolveReferences(); if (_confirmButton != null) { _confirmButton.onClick.AddListener(Confirm); } if (_cancelButton != null) { _cancelButton.onClick.AddListener(Cancel); } CloseImmediate(); } private void OnDestroy() { if (_confirmButton != null) { _confirmButton.onClick.RemoveListener(Confirm); } if (_cancelButton != null) { _cancelButton.onClick.RemoveListener(Cancel); } StopAndDispose(); } public void Open( string title, string message, string confirmText, string cancelText, Action onConfirm, Action onCancel) { _onConfirm = onConfirm; _onCancel = onCancel; if (_titleText != null) { _titleText.text = title; } if (_messageText != null) { _messageText.text = message; } if (_confirmLabel != null) { _confirmLabel.text = confirmText; } if (_cancelLabel != null) { _cancelLabel.text = cancelText; } OpenInternal().Forget(); } public void CancelFromBack() { Cancel(); } public void CloseImmediate() { StopAndDispose(); IsOpen = false; _onConfirm = null; _onCancel = null; if (_root != null) { _root.SetActive(false); } if (_canvasGroup != null) { _canvasGroup.alpha = 0f; _canvasGroup.interactable = false; _canvasGroup.blocksRaycasts = false; } if (_panelTransform != null) { _panelTransform.localScale = Vector3.one; } } private async UniTaskVoid OpenInternal() { ResolveReferences(); StopAndDispose(); _cts = new CancellationTokenSource(); if (_root != null) { _root.SetActive(true); } if (_canvasGroup != null) { _canvasGroup.alpha = 0f; _canvasGroup.interactable = false; _canvasGroup.blocksRaycasts = false; } if (_panelTransform != null) { _panelTransform.localScale = Vector3.one * _hiddenScale; } IsOpen = true; _sequence = Sequence.Create(useUnscaledTime: true); if (_canvasGroup != null) { _sequence.Group(Tween.Alpha(_canvasGroup, new TweenSettings { startValue = 0f, endValue = 1f, settings = _tweenSettings })); } if (_panelTransform != null) { _sequence.Group(Tween.Scale(_panelTransform, new TweenSettings { startValue = Vector3.one * _hiddenScale, endValue = Vector3.one, settings = _tweenSettings })); } try { await _sequence.ToUniTask(cancellationToken: _cts.Token); } catch (OperationCanceledException) { return; } finally { _sequence = default; } if (_canvasGroup != null) { _canvasGroup.alpha = 1f; _canvasGroup.interactable = true; _canvasGroup.blocksRaycasts = true; } SelectCancelButton(); } private void Confirm() { if (!IsOpen) { return; } var onConfirm = _onConfirm; CloseImmediate(); onConfirm?.Invoke(); } private void Cancel() { if (!IsOpen) { return; } var onCancel = _onCancel; CloseImmediate(); onCancel?.Invoke(); } private void ResolveReferences() { if (_root == null) { _root = gameObject; } if (_canvasGroup == null) { _canvasGroup = _root.GetComponent(); } if (_panelTransform == null) { _panelTransform = transform as RectTransform; } } private void SelectCancelButton() { if (_cancelButton == null) { return; } if (EventSystem.current != null) { EventSystem.current.SetSelectedGameObject(_cancelButton.gameObject); return; } _cancelButton.Select(); } private void StopAndDispose() { if (_sequence.isAlive) { _sequence.Stop(); } _sequence = default; if (_cts == null) { return; } try { _cts.Cancel(); } catch { } _cts.Dispose(); _cts = null; } } }