using System; using System.Threading; using BriarQueen.Framework.Managers.UI; using BriarQueen.Framework.Managers.UI.Base; using Cysharp.Threading.Tasks; using PrimeTween; using UnityEngine; using UnityEngine.UI; using VContainer; namespace BriarQueen.UI.HUD { /// /// Minimal HUD holder: /// - Registers itself with UIManager /// - Handles HUD visibility (alpha tween only) /// public class HUDContainer : MonoBehaviour, IHud { private const float DISPLAY_TIME = 4f; [Header("UI")] [SerializeField] private CursorTooltip _cursorTooltip; [SerializeField] private InteractTextUI _interactText; [Header("Inventory")] [SerializeField] private InventoryBar _inventoryBar; [Header("Components")] [SerializeField] private CanvasGroup _mainCanvasGroup; [SerializeField] private CanvasGroup _interactTextCanvasGroup; [Header("Tweens")] [SerializeField] private TweenSettings _tweenSettings = new() { duration = 0.2f, ease = Ease.InOutSine, useUnscaledTime = true }; [SerializeField] private GraphicRaycaster _graphicRaycaster; public GraphicRaycaster Raycaster => _graphicRaycaster; private CancellationTokenSource _cancellationTokenSource; private Sequence _hudSequence; private CancellationTokenSource _interactCancellationTokenSource; private Sequence _interactErrorSequence; private UIManager _uiManager; public CursorTooltip CursorTooltip => _cursorTooltip; public InventoryBar InventoryBar => _inventoryBar; private void Awake() { if (_mainCanvasGroup != null) { _mainCanvasGroup.alpha = 1f; _mainCanvasGroup.interactable = true; _mainCanvasGroup.blocksRaycasts = true; } if (_interactTextCanvasGroup != null) { _interactTextCanvasGroup.alpha = 0f; _interactTextCanvasGroup.blocksRaycasts = false; _interactTextCanvasGroup.interactable = false; } } private void OnDestroy() { StopTween(); StopInteractErrorTween(); } [Inject] public void Construct(UIManager uiManager) { _uiManager = uiManager; } // -------------------- // Visibility // -------------------- public async UniTask DisplayInteractText(string interactText) { if (_interactTextCanvasGroup == null || _interactText == null) return; // Cancel any in-flight error display and restart from current alpha. StopInteractErrorTween(); // Set text immediately. var text = interactText ?? string.Empty; _interactText.SetText(text); _interactCancellationTokenSource = new CancellationTokenSource(); var token = _interactCancellationTokenSource.Token; // Make sure it can show (but don't let it steal clicks). _interactTextCanvasGroup.blocksRaycasts = false; _interactTextCanvasGroup.interactable = false; var fadeIn = new TweenSettings { startValue = _interactTextCanvasGroup.alpha, endValue = 1f, settings = _tweenSettings }; var fadeOut = new TweenSettings { startValue = 1f, endValue = 0f, settings = _tweenSettings }; try { // Fade in _interactErrorSequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_interactTextCanvasGroup, fadeIn)); await _interactErrorSequence.ToUniTask(cancellationToken: token); _interactTextCanvasGroup.alpha = 1f; // Hold if (DISPLAY_TIME > 0f) await UniTask.Delay(TimeSpan.FromSeconds(DISPLAY_TIME), DelayType.UnscaledDeltaTime, cancellationToken: token); // Fade out _interactErrorSequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_interactTextCanvasGroup, fadeOut)); await _interactErrorSequence.ToUniTask(cancellationToken: token); _interactTextCanvasGroup.alpha = 0f; } catch (OperationCanceledException) { // If interrupted by a newer DisplayError call or destroy, just stop cleanly. } finally { if (_interactCancellationTokenSource != null) { _interactCancellationTokenSource.Dispose(); _interactCancellationTokenSource = null; } _interactErrorSequence = default; } } public async UniTask Show() { if (_mainCanvasGroup == null) return; StopTween(); _cancellationTokenSource = new CancellationTokenSource(); _mainCanvasGroup.blocksRaycasts = true; _mainCanvasGroup.interactable = true; var alphaTween = new TweenSettings { startValue = _mainCanvasGroup.alpha, endValue = 1f, settings = _tweenSettings }; _hudSequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_mainCanvasGroup, alphaTween)); try { await _hudSequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token); } catch (OperationCanceledException) { // interrupted by Hide / destroy — safe to ignore } _mainCanvasGroup.alpha = 1f; } public async UniTask Hide() { if (_mainCanvasGroup == null) return; StopTween(); _cancellationTokenSource = new CancellationTokenSource(); _mainCanvasGroup.blocksRaycasts = false; _mainCanvasGroup.interactable = false; var alphaTween = new TweenSettings { startValue = _mainCanvasGroup.alpha, endValue = 0f, settings = _tweenSettings }; _hudSequence = Sequence.Create(useUnscaledTime: true) .Group(Tween.Alpha(_mainCanvasGroup, alphaTween)); try { await _hudSequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token); } catch (OperationCanceledException) { // interrupted — safe } _mainCanvasGroup.alpha = 0f; } private void StopTween() { if (_hudSequence.isAlive) _hudSequence.Stop(); _hudSequence = default; if (_cancellationTokenSource != null) { _cancellationTokenSource.Cancel(); _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; } } private void StopInteractErrorTween() { if (_interactErrorSequence.isAlive) _interactErrorSequence.Stop(); _interactErrorSequence = default; if (_interactCancellationTokenSource != null) { try { _interactCancellationTokenSource.Cancel(); } catch { } _interactCancellationTokenSource.Dispose(); _interactCancellationTokenSource = null; } } private void OnMapClicked() { // Placeholder for later: // - open map window // - toggle map overlay } } }