Update pages to follow new card flow

This commit is contained in:
Michal Pikulski
2025-11-17 10:59:59 +01:00
parent 7aca1a17ac
commit ee07d89d3e
13 changed files with 2287 additions and 194 deletions

View File

@@ -137,12 +137,7 @@ namespace UI.CardSystem
for (int i = 0; i < boosterPackButtons.Length; i++)
{
if (boosterPackButtons[i] == null) continue;
// Unsubscribe from book events
if (book != null)
{
book.OnFlip.RemoveListener(OnPageFlipped);
}
Button button = boosterPackButtons[i].GetComponent<Button>();
if (button != null)
@@ -154,6 +149,12 @@ namespace UI.CardSystem
internal override void OnManagedDestroy()
{
// Unsubscribe from book events
if (book != null)
{
book.OnFlip.RemoveListener(OnPageFlipped);
}
// Unsubscribe from CardSystemManager
if (CardSystemManager.Instance != null)
{
@@ -182,8 +183,8 @@ namespace UI.CardSystem
}
}
// Clean up active cards
CleanupActiveCards();
// Clean up pending corner cards
CleanupPendingCornerCards();
}
private void OnExitButtonClicked()
@@ -271,7 +272,7 @@ namespace UI.CardSystem
if (IsInAlbumProper())
{
Logging.Debug("[AlbumViewPage] Opening directly to album page - spawning cards immediately");
SpawnPendingCards();
SpawnPendingCornerCards();
}
else
{
@@ -290,7 +291,7 @@ namespace UI.CardSystem
}
// Clean up active pending cards to prevent duplicates on next opening
CleanupActiveCards();
CleanupPendingCornerCards();
// Don't restore input mode here - only restore when actually exiting (in OnExitButtonClicked)
base.TransitionOut();
@@ -383,17 +384,17 @@ namespace UI.CardSystem
private void OnPageFlipped()
{
bool isInAlbum = IsInAlbumProper();
if (isInAlbum && _activeCards.Count == 0)
if (isInAlbum && _pendingCornerCards.Count == 0)
{
// Entering album proper and no cards spawned yet - spawn them with animation
Logging.Debug("[AlbumViewPage] Entering album proper - spawning pending cards with animation");
SpawnPendingCards();
SpawnPendingCornerCards();
}
else if (!isInAlbum && _activeCards.Count > 0)
else if (!isInAlbum && _pendingCornerCards.Count > 0)
{
// Returning to menu page - cleanup cards
Logging.Debug("[AlbumViewPage] Returning to menu page - cleaning up pending cards");
CleanupActiveCards();
CleanupPendingCornerCards();
}
else
{
@@ -696,6 +697,7 @@ namespace UI.CardSystem
{
card.SetupForAlbumPending();
card.AssignToSlot(slot, true);
card.Context.OnDragStarted += OnCardDragStarted;
_pendingCornerCards.Add(card);
}
else
@@ -709,28 +711,45 @@ namespace UI.CardSystem
{
foreach (var c in _pendingCornerCards)
{
if (c != null) Destroy(c.gameObject);
if (c != null)
{
if (c.Context != null)
{
c.Context.OnDragStarted -= OnCardDragStarted;
}
Destroy(c.gameObject);
}
}
_pendingCornerCards.Clear();
}
public void HandlePendingCardDragStart(StateMachine.Card cornerCard)
private void OnCardDragStarted(StateMachine.CardContext context)
{
if (context == null) return;
// Only handle if in PendingFaceDownState
var card = context.GetComponent<StateMachine.Card>();
if (card == null) return;
string stateName = card.GetCurrentStateName();
if (stateName != "PendingFaceDownState") return;
// Select smart pending card data
var selected = SelectSmartPendingCard();
if (selected == null)
{
return; // no pending data
}
cornerCard.Context.SetupCard(selected);
context.SetupCard(selected);
// Navigate album to page
int targetPage = FindPageForCard(selected);
if (targetPage >= 0)
{
NavigateToAlbumPage(targetPage);
}
// Begin flip state
cornerCard.ChangeState("FlippingPendingState");
// State will handle transition to FlippingPendingState
}
private CardData SelectSmartPendingCard()
@@ -749,19 +768,88 @@ namespace UI.CardSystem
private List<string> GetDefinitionsOnCurrentPage()
{
// Placeholder: gather from slots on current page
return new List<string>();
var result = new List<string>();
if (book == null) return result;
int currentPage = book.CurrentPaper;
// Find all AlbumCardSlot in scene
var allSlots = FindObjectsByType<AlbumCardSlot>(FindObjectsSortMode.None);
foreach (var slot in allSlots)
{
if (IsSlotOnPage(slot.transform, currentPage))
{
if (slot.TargetCardDefinition != null && !string.IsNullOrEmpty(slot.TargetCardDefinition.Id))
{
result.Add(slot.TargetCardDefinition.Id);
}
}
}
return result;
}
private bool IsSlotOnPage(Transform slotTransform, int pageIndex)
{
if (book == null || book.papers == null || pageIndex < 0 || pageIndex >= book.papers.Length)
return false;
var paper = book.papers[pageIndex];
if (paper == null) return false;
// Check if slotTransform parent hierarchy contains paper.Front or paper.Back
Transform current = slotTransform;
while (current != null)
{
if ((paper.Front != null && current.gameObject == paper.Front) ||
(paper.Back != null && current.gameObject == paper.Back))
return true;
current = current.parent;
}
return false;
}
private int FindPageForCard(CardData data)
{
// Placeholder: map definition to page index
if (data == null || book == null || book.papers == null) return -1;
// Find all AlbumCardSlot in scene
var allSlots = FindObjectsByType<AlbumCardSlot>(FindObjectsSortMode.None);
foreach (var slot in allSlots)
{
if (slot.TargetCardDefinition != null && slot.TargetCardDefinition.Id == data.DefinitionId)
{
// Found matching slot, now find which page it's on
for (int i = 0; i < book.papers.Length; i++)
{
if (IsSlotOnPage(slot.transform, i))
{
return i;
}
}
}
}
return -1;
}
private void NavigateToAlbumPage(int pageIndex)
{
// Placeholder: call book/page flip controller
if (book == null || pageIndex < 0) return;
// Get or add AutoFlip component
BookCurlPro.AutoFlip autoFlip = book.GetComponent<BookCurlPro.AutoFlip>();
if (autoFlip == null)
{
autoFlip = book.gameObject.AddComponent<BookCurlPro.AutoFlip>();
}
// Start flipping to target page
autoFlip.enabled = true;
autoFlip.StartFlipping(pageIndex);
}
}
}

View File

@@ -116,5 +116,10 @@ namespace UI.CardSystem
/// Get the target card definition for this slot
/// </summary>
public CardDefinition TargetCardDefinition => targetCardDefinition;
/// <summary>
/// Get the target card definition for this slot (method version for compatibility)
/// </summary>
public CardDefinition GetTargetCardDefinition() => targetCardDefinition;
}
}

View File

@@ -56,16 +56,20 @@ namespace UI.CardSystem.StateMachine
protected override void OnDragStartedHook()
{
base.OnDragStartedHook();
// Always emit the generic drag started event - consumers can decide what to do
context?.NotifyDragStarted();
string current = GetCurrentStateName();
if (current == "PendingFaceDownState")
{
// Notify AlbumViewPage to assign data & flip
var albumPage = FindObjectOfType<AlbumViewPage>();
if (albumPage != null)
// Let the state handle the flip transition
var pendingState = GetStateComponent<States.CardPendingFaceDownState>("PendingFaceDownState");
if (pendingState != null)
{
albumPage.HandlePendingCardDragStart(this);
pendingState.OnDragStarted();
}
// State change will be triggered by album page after data assignment
}
else
{

View File

@@ -38,6 +38,9 @@ namespace UI.CardSystem.StateMachine
// 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;
private bool _hasCompletedReveal = false;
public bool HasCompletedReveal => _hasCompletedReveal;
@@ -51,6 +54,12 @@ namespace UI.CardSystem.StateMachine
}
}
// Helper method for states/card to signal drag started
public void NotifyDragStarted()
{
OnDragStarted?.Invoke(this);
}
private void Awake()
{
// Auto-find components if not assigned

View File

@@ -1,57 +0,0 @@
using Core;
using Core.SaveLoad;
using UnityEngine;
namespace UI.CardSystem.StateMachine.States
{
/// <summary>
/// Handles flipping a pending face-down card after data assignment.
/// Transitions to DraggingRevealedState when flip completes.
/// </summary>
public class CardFlippingPendingState : AppleState
{
private CardContext context;
private GameObject cardBack;
private void Awake()
{
context = GetComponentInParent<CardContext>();
if (context != null)
{
var backTransform = context.RootTransform.Find("CardBack");
if (backTransform != null) cardBack = backTransform.gameObject;
}
}
public override void OnEnterState()
{
if (context == null) return;
// Ensure card back visible and front hidden at start
if (cardBack != null) cardBack.SetActive(true);
if (context.CardDisplay != null) context.CardDisplay.gameObject.SetActive(false);
// Optional: album navigation
var albumPage = Object.FindObjectOfType<AlbumViewPage>();
if (albumPage != null && context.CardData != null)
{
int targetPage = albumPage.FindPageForCard(context.CardData); // placeholder; method may be private
}
if (context.Animator != null)
{
Transform back = cardBack != null ? cardBack.transform : null;
Transform front = context.CardDisplay != null ? context.CardDisplay.transform : null;
context.Animator.PlayFlip(back, front, onComplete: () =>
{
context.StateMachine.ChangeState("DraggingRevealedState");
});
}
else
{
if (cardBack != null) cardBack.SetActive(false);
if (context.CardDisplay != null) context.CardDisplay.gameObject.SetActive(true);
context.StateMachine.ChangeState("DraggingRevealedState");
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: edffabfce37d42ceac2194c23470acab
timeCreated: 1763322190

View File

@@ -5,35 +5,97 @@ namespace UI.CardSystem.StateMachine.States
{
/// <summary>
/// Card is in pending face-down state in corner, awaiting drag.
/// Front hidden, back visible (assumes CardBack child exists).
/// On drag start, triggers data assignment, flip animation, and page navigation.
/// </summary>
public class CardPendingFaceDownState : AppleState
{
private CardContext context;
private GameObject cardBack;
[Header("State-Owned Visuals")]
[SerializeField] private GameObject cardBackVisual;
private CardContext _context;
private bool _isFlipping;
private void Awake()
{
context = GetComponentInParent<CardContext>();
if (context != null)
{
var backTransform = context.RootTransform.Find("CardBack");
if (backTransform != null) cardBack = backTransform.gameObject;
}
_context = GetComponentInParent<CardContext>();
}
public override void OnEnterState()
{
if (context == null) return;
// Hide front
if (context.CardDisplay != null)
if (_context == null) return;
_isFlipping = false;
// Show card back, hide card front
if (cardBackVisual != null)
{
context.CardDisplay.gameObject.SetActive(false);
cardBackVisual.SetActive(true);
cardBackVisual.transform.localRotation = Quaternion.Euler(0, 0, 0);
}
if (_context.CardDisplay != null)
{
_context.CardDisplay.gameObject.SetActive(false);
_context.CardDisplay.transform.localRotation = Quaternion.Euler(0, 180, 0);
}
// Scale down for corner display
_context.RootTransform.localScale = _context.OriginalScale * 0.8f;
}
/// <summary>
/// Called by Card.OnDragStartedHook when user starts dragging.
/// This triggers the smart selection, page navigation, and flip animation.
/// </summary>
public void OnDragStarted()
{
if (_isFlipping) return; // Already flipping
// Start flip animation (data should be assigned by listeners by now)
StartFlipAnimation();
}
private void StartFlipAnimation()
{
_isFlipping = true;
// Scale up from corner size to normal dragging size
if (_context.Animator != null)
{
_context.Animator.AnimateScale(_context.OriginalScale * 1.15f, 0.3f);
}
// Play flip animation
if (_context.Animator != null)
{
_context.Animator.PlayFlip(
cardBack: cardBackVisual != null ? cardBackVisual.transform : null,
cardFront: _context.CardDisplay != null ? _context.CardDisplay.transform : null,
onComplete: OnFlipComplete
);
}
else
{
// No animator, just switch visibility immediately
if (cardBackVisual != null) cardBackVisual.SetActive(false);
if (_context.CardDisplay != null) _context.CardDisplay.gameObject.SetActive(true);
OnFlipComplete();
}
}
private void OnFlipComplete()
{
// Transition to dragging revealed state
_context.StateMachine.ChangeState("DraggingRevealedState");
}
private void OnDisable()
{
// Hide card back when leaving state
if (cardBackVisual != null)
{
cardBackVisual.SetActive(false);
}
// Show back
if (cardBack != null) cardBack.SetActive(true);
// Scale
context.RootTransform.localScale = context.OriginalScale * 0.8f;
}
}
}

View File

@@ -56,7 +56,7 @@ namespace UI.CardSystem.Testing
{
_cardContext.OnRevealFlowComplete += OnCardRevealFlowComplete;
}
// Subscribe to drag events to ensure card snaps back when released
testCard.OnDragStarted += OnCardDragStarted;
testCard.OnDragEnded += OnCardDragEnded;