Merge a card refresh (#59)
- **Refactored Card Placement Flow** - Separated card presentation from orchestration logic - Extracted `CornerCardManager` for pending card lifecycle (spawn, shuffle, rebuild) - Extracted `AlbumNavigationService` for book page navigation and zone mapping - Extracted `CardEnlargeController` for backdrop management and card reparenting - Implemented controller pattern (non-MonoBehaviour) for complex logic - Cards now unparent from slots before rebuild to prevent premature destruction - **Improved Corner Card Display** - Fixed cards spawning on top of each other during rebuild - Implemented shuffle-to-front logic (remaining cards occupy slots 0→1→2) - Added smart card selection (prioritizes cards matching current album page) - Pending cards now removed from queue immediately on drag start - Corner cards rebuild after each placement with proper slot reassignment - **Enhanced Album Card Viewing** - Added dramatic scale increase when viewing cards from album slots - Implemented shrink animation when dismissing enlarged cards - Cards transition: `PlacedInSlotState` → `AlbumEnlargedState` → `PlacedInSlotState` - Backdrop shows/hides with card enlarge/shrink cycle - Cards reparent to enlarged container while viewing, return to slot after - **State Machine Improvements** - Added `CardStateNames` constants for type-safe state transitions - Implemented `ICardClickHandler` and `ICardStateDragHandler` interfaces - State transitions now use cached property indices - `BoosterCardContext` separated from `CardContext` for single responsibility - **Code Cleanup** - Identified unused `SlotContainerHelper.cs` (superseded by `CornerCardManager`) - Identified unused `BoosterPackDraggable.canOpenOnDrop` field - Identified unused `AlbumViewPage._previousInputMode` (hardcoded value) - Identified unused `Card.OnPlacedInAlbumSlot` event (no subscribers) Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Co-authored-by: Michal Pikulski <michal@foolhardyhorizons.com> Reviewed-on: #59
This commit is contained in:
172
Assets/Scripts/CardSystem/Controllers/AlbumNavigationService.cs
Normal file
172
Assets/Scripts/CardSystem/Controllers/AlbumNavigationService.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using System.Collections.Generic;
|
||||
using AppleHills.Data.CardSystem;
|
||||
using Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UI.CardSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages album page navigation, zone mapping, and page flip tracking.
|
||||
/// Created and owned by AlbumViewPage (not a Unity component).
|
||||
/// </summary>
|
||||
public class AlbumNavigationService
|
||||
{
|
||||
private readonly BookCurlPro.BookPro _book;
|
||||
private readonly BookTabButton[] _zoneTabs;
|
||||
|
||||
private bool _isPageFlipping = false;
|
||||
|
||||
/// <summary>
|
||||
/// Is the book currently flipping to a page?
|
||||
/// </summary>
|
||||
public bool IsPageFlipping => _isPageFlipping;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor - called by AlbumViewPage's lazy property
|
||||
/// </summary>
|
||||
public AlbumNavigationService(BookCurlPro.BookPro book, BookTabButton[] zoneTabs)
|
||||
{
|
||||
_book = book;
|
||||
_zoneTabs = zoneTabs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if we're currently viewing the album proper (not the menu page)
|
||||
/// </summary>
|
||||
public bool IsInAlbumProper()
|
||||
{
|
||||
if (_book == null)
|
||||
{
|
||||
Logging.Warning("[AlbumNavigationService] Book reference is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Page 1 is the menu/cover, page 2+ are album pages with card slots
|
||||
return _book.CurrentPaper > 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigate to the page where a specific card belongs
|
||||
/// </summary>
|
||||
public void NavigateToCardPage(CardData cardData, System.Action onComplete)
|
||||
{
|
||||
if (cardData == null || _book == null)
|
||||
{
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find target page based on card's zone
|
||||
int targetPage = FindPageForZone(cardData.Zone);
|
||||
|
||||
if (targetPage < 0)
|
||||
{
|
||||
Logging.Warning($"[AlbumNavigationService] No page found for zone {cardData.Zone}");
|
||||
onComplete?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as flipping
|
||||
_isPageFlipping = true;
|
||||
Logging.Debug($"[AlbumNavigationService] Starting page flip to page {targetPage}");
|
||||
|
||||
// Get or add AutoFlip component
|
||||
BookCurlPro.AutoFlip autoFlip = _book.GetComponent<BookCurlPro.AutoFlip>();
|
||||
if (autoFlip == null)
|
||||
{
|
||||
autoFlip = _book.gameObject.AddComponent<BookCurlPro.AutoFlip>();
|
||||
}
|
||||
|
||||
// Start flipping with callback
|
||||
autoFlip.enabled = true;
|
||||
autoFlip.StartFlipping(targetPage, () =>
|
||||
{
|
||||
// Mark as complete
|
||||
_isPageFlipping = false;
|
||||
Logging.Debug($"[AlbumNavigationService] Page flip to {targetPage} completed");
|
||||
|
||||
// Call original callback if provided
|
||||
onComplete?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get list of card definition IDs on the current page
|
||||
/// </summary>
|
||||
public List<string> GetDefinitionsOnCurrentPage()
|
||||
{
|
||||
var result = new List<string>();
|
||||
if (_book == null) return result;
|
||||
|
||||
int currentPage = _book.CurrentPaper;
|
||||
|
||||
// Find all AlbumCardSlot in scene
|
||||
var allSlots = Object.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;
|
||||
}
|
||||
|
||||
#region Private Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Find the target page for a card zone using BookTabButtons
|
||||
/// </summary>
|
||||
private int FindPageForZone(CardZone zone)
|
||||
{
|
||||
if (_zoneTabs == null || _zoneTabs.Length == 0)
|
||||
{
|
||||
Logging.Warning("[AlbumNavigationService] No zone tabs available!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
foreach (var tab in _zoneTabs)
|
||||
{
|
||||
if (tab.Zone == zone)
|
||||
{
|
||||
return tab.TargetPage;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Warning($"[AlbumNavigationService] No BookTabButton found for zone {zone}");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a slot's transform is on a specific book page
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user