Files
Echo/Assets/_Project/Scripts/UI/SpecialUsePopupController.cs
2026-07-08 20:42:51 +08:00

233 lines
7.1 KiB
C#

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<Image>(true)?.rectTransform;
}
if (popupImage == null)
{
popupImage = popupImageRect != null ? popupImageRect.GetComponent<Image>() : GetComponentInChildren<Image>(true);
}
if (popupText == null)
{
popupText = GetComponentInChildren<TMP_Text>(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;
}
}
}