using DG.Tweening; using TMPro; using Core.InputLock; using UnityEngine; using UnityEngine.UI; using UI.PanelStack; using Michsky.UI.Reach; namespace UI { public class SpecialUsePopupController : MonoBehaviour { public static SpecialUsePopupController Instance { get; private set; } [Header("UI References")] [SerializeField] private RectTransform popupImageRect; [SerializeField] private Image popupImage; [SerializeField] private TMP_Text popupText; [Header("Buttons")] [SerializeField] private ButtonManager closeButton; [SerializeField] private ButtonManager previousPageButton; [SerializeField] private ButtonManager nextPageButton; [Header("Animation")] [SerializeField] private float hiddenY = -600f; [SerializeField] private float shownY = 0f; [SerializeField] private float tweenDuration = 0.35f; [SerializeField] private Ease tweenEase = Ease.OutCubic; [Header("Control")] [SerializeField] private bool lockPlayerControl = true; [SerializeField] private bool usePanelStackEscapeClose = true; private Sequence sequence; private string[] pages; private int pageIndex; private bool isOpen; private void Awake() { if (Instance == null) Instance = this; else { Destroy(gameObject); return; } if (popupImageRect == null) { popupImageRect = GetComponentInChildren(true)?.rectTransform; } if (popupImage == null) { popupImage = popupImageRect != null ? popupImageRect.GetComponent() : GetComponentInChildren(true); } if (popupText == null) { popupText = GetComponentInChildren(true); } if (closeButton != null) { closeButton.onClick.RemoveListener(Close); closeButton.onClick.AddListener(Close); } if (previousPageButton != null) { previousPageButton.onClick.RemoveListener(PreviousPage); previousPageButton.onClick.AddListener(PreviousPage); } if (nextPageButton != null) { nextPageButton.onClick.RemoveListener(NextPage); nextPageButton.onClick.AddListener(NextPage); } Hide(true); } public void ShowPages(string[] pageTexts, Sprite sprite = null, int startPageIndex = 0) { if (popupImageRect == null) return; pages = pageTexts != null && pageTexts.Length > 0 ? pageTexts : new[] { string.Empty }; pageIndex = Mathf.Clamp(startPageIndex, 0, pages.Length - 1); SetPageText(); if (sprite != null && popupImage != null) { popupImage.sprite = sprite; } Open(); } private void Open() { if (isOpen) return; isOpen = true; gameObject.SetActive(true); popupImageRect.gameObject.SetActive(true); if (usePanelStackEscapeClose && UIPanelStack.Instance != null) { UIPanelStack.Instance.Push(UIPanelKind.Custom, gameObject, CloseFromPanelStack); } if (lockPlayerControl && PlayerControlLockService.Instance != null) { PlayerControlLockService.Instance.Lock(this); } popupImageRect.anchoredPosition = new Vector2(popupImageRect.anchoredPosition.x, hiddenY); sequence?.Kill(); sequence = DOTween.Sequence(); sequence.Append(popupImageRect.DOAnchorPosY(shownY, tweenDuration).SetEase(tweenEase)); } public void Close() { if (!isOpen) return; if (UIPanelStack.Instance != null) UIPanelStack.Instance.Remove(gameObject); Hide(false); } private void CloseFromPanelStack() { if (!isOpen) return; Hide(false); } private void PreviousPage() { if (!isOpen) return; if (pages == null || pages.Length == 0) return; if (pageIndex <= 0) return; pageIndex--; SetPageText(); } private void NextPage() { if (!isOpen) return; if (pages == null || pages.Length == 0) return; if (pageIndex >= pages.Length - 1) return; pageIndex++; SetPageText(); } private void SetPageText() { if (popupText != null) { if (pages != null && pages.Length > 0) { int safeIndex = Mathf.Clamp(pageIndex, 0, pages.Length - 1); popupText.text = pages[safeIndex] ?? string.Empty; } else { popupText.text = string.Empty; } } bool hasPages = pages != null && pages.Length > 1; if (previousPageButton != null) { previousPageButton.gameObject.SetActive(hasPages); previousPageButton.Interactable(hasPages && pageIndex > 0); } if (nextPageButton != null) { nextPageButton.gameObject.SetActive(hasPages); nextPageButton.Interactable(hasPages && pageIndex < pages.Length - 1); } } public void Hide(bool immediate) { if (popupImageRect == null) return; sequence?.Kill(); sequence = null; if (immediate) { popupImageRect.anchoredPosition = new Vector2(popupImageRect.anchoredPosition.x, hiddenY); popupImageRect.gameObject.SetActive(false); gameObject.SetActive(false); if (lockPlayerControl && PlayerControlLockService.Instance != null) { PlayerControlLockService.Instance.Unlock(this); } isOpen = false; return; } sequence = DOTween.Sequence(); sequence.Append(popupImageRect.DOAnchorPosY(hiddenY, tweenDuration).SetEase(Ease.InCubic)); sequence.AppendCallback(() => { popupImageRect.gameObject.SetActive(false); gameObject.SetActive(false); if (lockPlayerControl && PlayerControlLockService.Instance != null) { PlayerControlLockService.Instance.Unlock(this); } isOpen = false; }); } private void OnDisable() { if (!isOpen) return; sequence?.Kill(); sequence = null; if (lockPlayerControl && PlayerControlLockService.Instance != null) { PlayerControlLockService.Instance.Unlock(this); } isOpen = false; } } }