78bfdf2828
# Conflicts: # Assets/External/Animated PBR Chest Demo/Materials/WoodChest.mat # Packages/com.distantlands.cozy.core/Content/Integration/Import for BiRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for HDRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for URP.unitypackage.meta
194 lines
6.3 KiB
C#
194 lines
6.3 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using DG.Tweening;
|
|
using Ashwild.Inventory;
|
|
|
|
namespace Ashwild.UI
|
|
{
|
|
public class NotificationItemUI : MonoBehaviour
|
|
{
|
|
[Header("References")]
|
|
[SerializeField] private Image iconImage;
|
|
[SerializeField] private TextMeshProUGUI labelText; // item name only
|
|
[SerializeField] private TextMeshProUGUI numberText; // signed context: +N / -N
|
|
[SerializeField] private CanvasGroup canvasGroup;
|
|
[SerializeField] private RectTransform rectTransform;
|
|
|
|
private ItemData itemData;
|
|
private int totalQuantity;
|
|
private float hideTimer;
|
|
private bool isHiding;
|
|
private bool isDiscovery;
|
|
private string message;
|
|
|
|
private Tweener fadeTween;
|
|
private Tweener slideTween;
|
|
private Tweener punchTween;
|
|
|
|
public ItemData ItemData => itemData;
|
|
public RectTransform RectTransform => rectTransform;
|
|
|
|
// A notification is either a gain (+) or a loss (-); merging only happens within the same direction.
|
|
public bool IsGain => totalQuantity >= 0;
|
|
|
|
// A discovery notification (icon + name + "NEW" badge) never merges with a gain/loss one.
|
|
public bool IsDiscovery => isDiscovery;
|
|
|
|
// The refusal text this notification shows, or null when it is not a message — used to collapse
|
|
// repeats of the same reason onto the line already on screen.
|
|
public string Message => message;
|
|
|
|
public void Initialize(ItemData item, int signedQuantity, Color numberColor, float displayDuration, float slideInDuration, Ease slideInEase)
|
|
{
|
|
itemData = item;
|
|
totalQuantity = signedQuantity;
|
|
hideTimer = displayDuration;
|
|
isHiding = false;
|
|
|
|
if (iconImage != null)
|
|
iconImage.sprite = item.Icon;
|
|
|
|
if (numberText != null)
|
|
numberText.color = numberColor;
|
|
|
|
UpdateLabel();
|
|
|
|
canvasGroup.alpha = 0f;
|
|
fadeTween = canvasGroup.DOFade(1f, slideInDuration).SetEase(Ease.OutQuad);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up a discovery notification: an icon and name (of the unlocked recipe) with a fixed
|
|
/// badge (e.g. "NEW") in the number slot, tinted with the caller-chosen colour. It carries no
|
|
/// quantity and never merges, so it reads as a one-time "recipe unlocked" cue.
|
|
/// </summary>
|
|
public void InitializeDiscovery(Sprite icon, string displayName, string badgeText, Color badgeColor, float displayDuration, float slideInDuration)
|
|
{
|
|
itemData = null;
|
|
isDiscovery = true;
|
|
hideTimer = displayDuration;
|
|
isHiding = false;
|
|
|
|
if (iconImage != null)
|
|
iconImage.sprite = icon;
|
|
|
|
if (labelText != null)
|
|
labelText.text = displayName;
|
|
|
|
if (numberText != null)
|
|
{
|
|
numberText.text = badgeText;
|
|
numberText.color = badgeColor;
|
|
}
|
|
|
|
canvasGroup.alpha = 0f;
|
|
fadeTween = canvasGroup.DOFade(1f, slideInDuration).SetEase(Ease.OutQuad);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up a plain message notification: a reason (e.g. "Inventory full") with no icon and no
|
|
/// number, tinted by the caller. It carries no item, so it never merges with a gain/loss — a
|
|
/// refusal is a one-off statement, not a running total.
|
|
/// </summary>
|
|
public void InitializeMessage(string text, Color messageColor, float displayDuration, float slideInDuration)
|
|
{
|
|
itemData = null;
|
|
isDiscovery = true;
|
|
message = text;
|
|
hideTimer = displayDuration;
|
|
isHiding = false;
|
|
|
|
if (iconImage != null)
|
|
iconImage.gameObject.SetActive(false);
|
|
|
|
if (labelText != null)
|
|
{
|
|
labelText.text = text;
|
|
labelText.color = messageColor;
|
|
}
|
|
|
|
if (numberText != null)
|
|
numberText.text = string.Empty;
|
|
|
|
canvasGroup.alpha = 0f;
|
|
fadeTween = canvasGroup.DOFade(1f, slideInDuration).SetEase(Ease.OutQuad);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restarts the display timer of a message already on screen, so repeating the same refused
|
|
/// action keeps one line alive instead of queueing a duplicate behind it.
|
|
/// </summary>
|
|
public void RefreshMessage(float displayDuration)
|
|
{
|
|
hideTimer = displayDuration;
|
|
|
|
if (isHiding)
|
|
{
|
|
isHiding = false;
|
|
fadeTween?.Kill();
|
|
slideTween?.Kill();
|
|
canvasGroup.alpha = 1f;
|
|
}
|
|
}
|
|
|
|
public void AddQuantity(int signedAmount, float displayDuration)
|
|
{
|
|
totalQuantity += signedAmount;
|
|
UpdateLabel();
|
|
hideTimer = displayDuration;
|
|
|
|
if (isHiding)
|
|
{
|
|
isHiding = false;
|
|
fadeTween?.Kill();
|
|
slideTween?.Kill();
|
|
canvasGroup.alpha = 1f;
|
|
}
|
|
|
|
punchTween?.Kill();
|
|
if (iconImage != null)
|
|
punchTween = iconImage.transform.DOPunchScale(Vector3.one * 0.15f, 0.25f, 5, 0.5f);
|
|
}
|
|
|
|
private void UpdateLabel()
|
|
{
|
|
if (labelText != null)
|
|
labelText.text = itemData.ItemName;
|
|
|
|
if (numberText != null)
|
|
numberText.text = (totalQuantity >= 0 ? "+" : "-") + Mathf.Abs(totalQuantity);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (isHiding) return;
|
|
|
|
hideTimer -= Time.deltaTime;
|
|
if (hideTimer <= 0f)
|
|
Hide();
|
|
}
|
|
|
|
public void Hide()
|
|
{
|
|
if (isHiding) return;
|
|
isHiding = true;
|
|
|
|
fadeTween?.Kill();
|
|
slideTween?.Kill();
|
|
|
|
fadeTween = canvasGroup.DOFade(0f, 0.3f).SetEase(Ease.InQuad);
|
|
slideTween = rectTransform.DOAnchorPosX(rectTransform.anchoredPosition.x - 200f, 0.3f)
|
|
.SetEase(Ease.InQuad)
|
|
.OnComplete(() => Destroy(gameObject));
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
fadeTween?.Kill();
|
|
slideTween?.Kill();
|
|
punchTween?.Kill();
|
|
}
|
|
}
|
|
}
|