using System; using System.Threading; using BriarQueen.Framework.Coordinators.Events; using BriarQueen.Framework.Events.UI; using BriarQueen.Framework.Managers.Audio; using BriarQueen.Framework.Managers.Interaction; using BriarQueen.Framework.Managers.IO; using BriarQueen.Framework.Managers.UI.Base; using BriarQueen.Framework.Managers.UI.Events; using BriarQueen.Framework.Services.Game; using Cysharp.Threading.Tasks; using PrimeTween; using UnityEngine; using UnityEngine.UI; using VContainer; namespace BriarQueen.UI.Menus { public class PauseMenuWindow : MonoBehaviour, IUIWindow { [Header("Root UI")] [SerializeField] private CanvasGroup _canvasGroup; [SerializeField] private RectTransform _windowRect; [Header("Buttons")] [SerializeField] private Button _resumeButton; [SerializeField] private Button _saveButton; [SerializeField] private Button _settingsButton; [SerializeField] private Button _exitButton; [SerializeField] private Button _quitToDesktopButton; [Header("Tween Settings")] [SerializeField] private TweenSettings _tweenSettings = new() { duration = 0.25f, ease = Ease.OutQuad, useUnscaledTime = true }; [Header("Scale")] [SerializeField] private float _hiddenScale = 0.85f; [Header("Internal")] [SerializeField] private GraphicRaycaster _graphicRaycaster; private AudioManager _audioManager; private CancellationTokenSource _cts; private EventCoordinator _eventCoordinator; private GameService _gameService; private InteractManager _interactManager; private SaveManager _saveManager; private Sequence _sequence; public bool IsModal => true; public WindowType WindowType => WindowType.PauseMenuWindow; private void Awake() { // Start hidden by default if (_canvasGroup != null) { _canvasGroup.alpha = 0f; _canvasGroup.blocksRaycasts = false; _canvasGroup.interactable = false; } if (_windowRect != null) _windowRect.localScale = Vector3.one * _hiddenScale; } private void OnEnable() { if (_resumeButton != null) _resumeButton.onClick.AddListener(OnResumeButtonClick); if (_saveButton != null) _saveButton.onClick.AddListener(OnSaveButtonClick); if (_settingsButton != null) _settingsButton.onClick.AddListener(OnSettingsButtonClick); if (_exitButton != null) _exitButton.onClick.AddListener(OnExitButtonClick); if (_quitToDesktopButton != null) _quitToDesktopButton.onClick.AddListener(OnQuitToDesktopButtonClick); _interactManager.SetExclusiveRaycaster(_graphicRaycaster); } private void OnDisable() { if (_resumeButton != null) _resumeButton.onClick.RemoveListener(OnResumeButtonClick); if (_saveButton != null) _saveButton.onClick.RemoveListener(OnSaveButtonClick); if (_settingsButton != null) _settingsButton.onClick.RemoveListener(OnSettingsButtonClick); if (_exitButton != null) _exitButton.onClick.RemoveListener(OnExitButtonClick); if (_quitToDesktopButton != null) _quitToDesktopButton.onClick.RemoveListener(OnQuitToDesktopButtonClick); _interactManager.ClearExclusiveRaycaster(); } private void OnDestroy() { StopAndResetCancellation(); } public async UniTask Show() { if (_canvasGroup == null || _windowRect == null) { Debug.LogError("[PauseMenuWindow] Missing CanvasGroup or WindowRect reference."); gameObject.SetActive(true); return; } StopAndResetCancellation(); gameObject.SetActive(true); _canvasGroup.alpha = 0f; _canvasGroup.blocksRaycasts = false; _canvasGroup.interactable = false; _windowRect.localScale = Vector3.one * _hiddenScale; var alpha = new TweenSettings { startValue = 0f, endValue = 1f, settings = _tweenSettings }; var scale = new TweenSettings { startValue = Vector3.one * _hiddenScale, endValue = Vector3.one, settings = _tweenSettings }; _sequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_canvasGroup, alpha)) .Group(Tween.Scale(_windowRect, scale)); try { await _sequence.ToUniTask(cancellationToken: _cts.Token); } catch (OperationCanceledException) { return; } finally { _sequence = default; } _canvasGroup.alpha = 1f; _windowRect.localScale = Vector3.one; _canvasGroup.blocksRaycasts = true; _canvasGroup.interactable = true; } public async UniTask Hide() { if (_canvasGroup == null || _windowRect == null) { gameObject.SetActive(false); return; } StopAndResetCancellation(); // Block clicks immediately _canvasGroup.blocksRaycasts = false; _canvasGroup.interactable = false; var alpha = new TweenSettings { startValue = _canvasGroup.alpha, endValue = 0f, settings = _tweenSettings }; var scale = new TweenSettings { startValue = _windowRect.localScale, endValue = Vector3.one * _hiddenScale, settings = _tweenSettings }; _sequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_canvasGroup, alpha)) .Group(Tween.Scale(_windowRect, scale)); try { await _sequence.ToUniTask(cancellationToken: _cts.Token); } catch (OperationCanceledException) { return; } finally { _sequence = default; } _canvasGroup.alpha = 0f; _windowRect.localScale = Vector3.one * _hiddenScale; gameObject.SetActive(false); } [Inject] public void Construct(EventCoordinator eventCoordinator, SaveManager saveManager, GameService gameService, InteractManager interactManager, AudioManager audioManager) { _eventCoordinator = eventCoordinator; _saveManager = saveManager; _gameService = gameService; _interactManager = interactManager; _audioManager = audioManager; } private void StopAndResetCancellation() { if (_sequence.isAlive) _sequence.Stop(); if (_cts != null) { try { _cts.Cancel(); } catch { } _cts.Dispose(); _cts = null; } _cts = new CancellationTokenSource(); } private void OnResumeButtonClick() { _eventCoordinator?.Publish(new PauseButtonClickedEvent()); } private void OnSaveButtonClick() { SaveGame().Forget(); } private void OnSettingsButtonClick() { _eventCoordinator.Publish(new UIToggleSettingsWindow(true)); } private void OnExitButtonClick() { _eventCoordinator.Publish(new FadeEvent(false, 1f)); ExitButtonInternal().Forget(); } private async UniTask ExitButtonInternal() { await UniTask.Delay(TimeSpan.FromSeconds(1)); _audioManager.StopAllAudio(); await SaveGame(); _eventCoordinator.Publish(new PauseButtonClickedEvent()); await _gameService.LoadMainMenu(); } private void OnQuitToDesktopButtonClick() { QuitButtonInternal().Forget(); } private async UniTask QuitButtonInternal() { _eventCoordinator.Publish(new FadeEvent(false, 1f)); await UniTask.Delay(TimeSpan.FromSeconds(1)); await SaveGame(); _gameService.QuitGame(); } private async UniTask SaveGame() { if (_saveManager == null) return; await _saveManager.SaveGameDataLatest(); // TODO: Saved feedback popup/toast } } }