191 lines
6.6 KiB
C#
191 lines
6.6 KiB
C#
using System;
|
||
using AppleHills.Data.CardSystem;
|
||
using Core.SaveLoad;
|
||
using UnityEngine;
|
||
|
||
namespace UI.CardSystem.StateMachine
|
||
{
|
||
/// <summary>
|
||
/// Shared context for card states.
|
||
/// Provides access to common components and data that states need.
|
||
/// </summary>
|
||
public class CardContext : MonoBehaviour
|
||
{
|
||
[Header("Core Components")]
|
||
[SerializeField] private CardDisplay cardDisplay;
|
||
[SerializeField] private CardAnimator cardAnimator;
|
||
private AppleMachine stateMachine;
|
||
|
||
[Header("Card Data")]
|
||
private CardData cardData;
|
||
|
||
// Cached reference to AlbumViewPage (lazy-loaded)
|
||
private AlbumViewPage _albumViewPage;
|
||
|
||
// Public accessors
|
||
public CardDisplay CardDisplay => cardDisplay;
|
||
public CardAnimator Animator => cardAnimator;
|
||
public AppleMachine StateMachine => stateMachine;
|
||
public Transform RootTransform => transform;
|
||
public CardData CardData => cardData;
|
||
|
||
/// <summary>
|
||
/// Get the AlbumViewPage instance (cached to avoid repeated FindFirstObjectByType calls)
|
||
/// </summary>
|
||
public AlbumViewPage AlbumViewPage
|
||
{
|
||
get
|
||
{
|
||
if (_albumViewPage == null)
|
||
{
|
||
_albumViewPage = FindFirstObjectByType<AlbumViewPage>();
|
||
}
|
||
return _albumViewPage;
|
||
}
|
||
}
|
||
|
||
// Runtime state
|
||
public bool IsClickable { get; set; } = true;
|
||
|
||
// TODO: Move to booster-specific states - this is workflow-specific, not generic context
|
||
public bool SuppressRevealBadges { get; set; } = false; // Set by states to suppress NEW/REPEAT badges in revealed state
|
||
|
||
// Original transform data (captured on spawn for shrink animations)
|
||
public Vector3 OriginalScale { get; private set; }
|
||
public Vector3 OriginalPosition { get; private set; }
|
||
public Quaternion OriginalRotation { get; private set; }
|
||
|
||
// TODO: Move to BoosterOpeningPage - reveal flow is booster-specific workflow coordination
|
||
// Single event for reveal flow completion
|
||
public event Action<CardContext> OnRevealFlowComplete;
|
||
|
||
// Generic drag event - fired when drag starts, consumers decide how to handle based on current state
|
||
public event Action<CardContext> OnDragStarted;
|
||
|
||
// Generic drag end event - fired when drag ends, consumers decide how to handle based on current state
|
||
public event Action<CardContext> OnDragEnded;
|
||
|
||
// TODO: Move to booster-specific states - this tracks reveal workflow completion
|
||
private bool _hasCompletedReveal = false;
|
||
public bool HasCompletedReveal => _hasCompletedReveal;
|
||
|
||
// TODO: Move to booster-specific states - workflow coordination method
|
||
// Helper method for states to signal completion
|
||
public void NotifyRevealComplete()
|
||
{
|
||
if (!_hasCompletedReveal)
|
||
{
|
||
_hasCompletedReveal = true;
|
||
OnRevealFlowComplete?.Invoke(this);
|
||
}
|
||
}
|
||
|
||
// Helper method for states/card to signal drag started
|
||
public void NotifyDragStarted()
|
||
{
|
||
OnDragStarted?.Invoke(this);
|
||
}
|
||
|
||
// Helper method for states/card to signal drag ended
|
||
public void NotifyDragEnded()
|
||
{
|
||
OnDragEnded?.Invoke(this);
|
||
}
|
||
|
||
private void Awake()
|
||
{
|
||
// Auto-find components if not assigned
|
||
if (cardDisplay == null)
|
||
cardDisplay = GetComponentInChildren<CardDisplay>();
|
||
|
||
if (cardAnimator == null)
|
||
cardAnimator = GetComponent<CardAnimator>();
|
||
|
||
if (stateMachine == null)
|
||
stateMachine = GetComponentInChildren<AppleMachine>();
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
// Subscribe to CardDisplay click and route to active state
|
||
if (cardDisplay != null)
|
||
{
|
||
cardDisplay.OnCardClicked += HandleCardDisplayClicked;
|
||
}
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (cardDisplay != null)
|
||
{
|
||
cardDisplay.OnCardClicked -= HandleCardDisplayClicked;
|
||
}
|
||
}
|
||
|
||
private void HandleCardDisplayClicked(CardDisplay _)
|
||
{
|
||
// Gate by clickability
|
||
if (!IsClickable) return;
|
||
if (stateMachine == null || stateMachine.currentState == null) return;
|
||
|
||
var handler = stateMachine.currentState.GetComponent<ICardClickHandler>();
|
||
if (handler != null)
|
||
{
|
||
handler.OnCardClicked(this);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Setup the card with data
|
||
/// </summary>
|
||
public void SetupCard(CardData data)
|
||
{
|
||
cardData = data;
|
||
_hasCompletedReveal = false; // Reset completion flag
|
||
|
||
// Capture original transform for shrink animations.
|
||
// If current scale is ~0 (pop-in staging), default to Vector3.one.
|
||
var currentScale = transform.localScale;
|
||
if (currentScale.x < 0.01f && currentScale.y < 0.01f && currentScale.z < 0.01f)
|
||
{
|
||
OriginalScale = Vector3.one;
|
||
}
|
||
else
|
||
{
|
||
OriginalScale = currentScale;
|
||
}
|
||
OriginalPosition = transform.localPosition;
|
||
OriginalRotation = transform.localRotation;
|
||
|
||
if (cardDisplay != null)
|
||
{
|
||
cardDisplay.SetupCard(data);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Update card data without re-capturing original transform values.
|
||
/// Use this when assigning data to an already-initialized card (e.g., pending cards on drag).
|
||
/// This prevents changing OriginalScale when the card is already correctly sized.
|
||
/// </summary>
|
||
public void UpdateCardData(CardData data)
|
||
{
|
||
cardData = data;
|
||
_hasCompletedReveal = false; // Reset completion flag
|
||
|
||
// Don't re-capture OriginalScale/Position/Rotation
|
||
// This preserves the transform values captured during initial setup
|
||
|
||
if (cardDisplay != null)
|
||
{
|
||
cardDisplay.SetupCard(data);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the card display component
|
||
/// </summary>
|
||
public CardDisplay GetCardDisplay() => cardDisplay;
|
||
}
|
||
}
|