2025-11-07 01:51:03 +01:00
using System ;
using System.Collections ;
using AppleHills.Data.CardSystem ;
using Data.CardSystem ;
2025-11-07 11:24:19 +01:00
using Pixelplacement ;
2025-11-07 01:51:03 +01:00
using UI.DragAndDrop.Core ;
using UnityEngine ;
namespace UI.CardSystem
{
/// <summary>
/// Draggable card for album reveal system.
/// Handles both tap and drag-hold interactions for revealing cards.
/// Auto-snaps to matching album slot on release/tap.
/// </summary>
2025-11-07 11:24:19 +01:00
public class AlbumCardPlacementDraggable : DraggableObject
2025-11-07 01:51:03 +01:00
{
[Header("Album Card Settings")]
[SerializeField] private FlippableCard flippableCard ;
[SerializeField] private float holdRevealDelay = 0.1f ;
private CardData _cardData ;
private bool _isRevealed = false ;
private bool _isDragRevealing = false ;
private bool _waitingForPlacementTap = false ;
private Coroutine _holdRevealCoroutine ;
private bool _isHolding = false ; // Track if pointer is currently down
// Events
2025-11-07 11:24:19 +01:00
public event Action < AlbumCardPlacementDraggable , CardData > OnCardRevealed ;
public event Action < AlbumCardPlacementDraggable , CardData > OnCardPlacedInAlbum ;
2025-11-07 01:51:03 +01:00
public CardData CardData = > _cardData ;
public bool IsRevealed = > _isRevealed ;
public CardZone Zone = > _cardData ? . Zone ? ? CardZone . AppleHills ;
protected override void Initialize ( )
{
base . Initialize ( ) ;
// Auto-find FlippableCard if not assigned
if ( flippableCard = = null )
{
flippableCard = GetComponent < FlippableCard > ( ) ;
}
}
/// <summary>
/// Setup the card data (stores it but doesn't reveal until tapped/dragged)
/// </summary>
public void SetupCard ( CardData data )
{
_cardData = data ;
if ( flippableCard ! = null )
{
flippableCard . SetupCard ( data ) ;
}
}
/// <summary>
/// Reveal the card (flip to show front)
/// </summary>
public void RevealCard ( )
{
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] RevealCard() called - _isRevealed: {_isRevealed}" ) ;
if ( _isRevealed )
{
Debug . LogWarning ( $"[PAGE-NAV-DEBUG] Card already revealed, skipping reveal" ) ;
return ;
}
2025-11-07 01:51:03 +01:00
_isRevealed = true ;
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] Setting _isRevealed = true, card zone: {(_cardData != null ? _cardData.Zone.ToString() : " NULL ")}" ) ;
2025-11-07 01:51:03 +01:00
if ( flippableCard ! = null )
{
flippableCard . FlipToReveal ( ) ;
}
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] Invoking OnCardRevealed event (subscribers: {(OnCardRevealed != null ? OnCardRevealed.GetInvocationList().Length : 0)})" ) ;
2025-11-07 01:51:03 +01:00
OnCardRevealed ? . Invoke ( this , _cardData ) ;
}
/// <summary>
/// Snap to the matching album slot
/// </summary>
public void SnapToAlbumSlot ( )
{
if ( _cardData = = null )
{
2025-11-07 11:24:19 +01:00
Debug . LogWarning ( "[AlbumCardPlacementDraggable] Cannot snap to slot - no card data assigned." ) ;
2025-11-07 01:51:03 +01:00
return ;
}
// Find all album card slots in the scene
AlbumCardSlot [ ] allSlots = FindObjectsByType < AlbumCardSlot > ( FindObjectsSortMode . None ) ;
AlbumCardSlot matchingSlot = null ;
foreach ( var slot in allSlots )
{
if ( slot . CanAcceptCard ( _cardData ) )
{
matchingSlot = slot ;
break ;
}
}
if ( matchingSlot ! = null )
{
2025-11-07 11:24:19 +01:00
SetDraggingEnabled ( false ) ;
2025-11-07 01:51:03 +01:00
2025-11-07 11:24:19 +01:00
// NEW FLOW: Extract AlbumCard FIRST, then tween it
if ( flippableCard ! = null )
{
AlbumCard extractedCard = flippableCard . ExtractAlbumCard ( matchingSlot . transform ) ;
if ( extractedCard ! = null )
{
// Notify slot that card was placed
matchingSlot . OnCardPlaced ( extractedCard ) ;
// NOW tween the extracted AlbumCard into position
TweenExtractedCardToSlot ( extractedCard , ( ) = >
{
// After animation completes
Debug . Log ( $"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}" ) ;
// Notify that card was placed
OnCardPlacedInAlbum ? . Invoke ( this , _cardData ) ;
// Destroy this wrapper (the AlbumPlacementCard)
Destroy ( gameObject ) ;
} ) ;
}
else
{
Debug . LogWarning ( "[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!" ) ;
}
}
}
else
{
Debug . LogWarning ( $"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})" ) ;
}
}
/// <summary>
/// Tween the extracted AlbumCard into its slot position
/// Tweens from current size to slot size - AspectRatioFitter handles width
/// </summary>
private void TweenExtractedCardToSlot ( AlbumCard card , System . Action onComplete )
{
Transform cardTransform = card . transform ;
RectTransform cardRect = cardTransform as RectTransform ;
if ( cardRect ! = null )
{
// Get target height from slot
RectTransform slotRect = cardTransform . parent as RectTransform ;
float targetHeight = slotRect ! = null ? slotRect . rect . height : cardRect . sizeDelta . y ;
2025-11-07 01:51:03 +01:00
2025-11-07 11:24:19 +01:00
// Tween from current size to target size (AspectRatioFitter will adjust width)
Vector2 targetSize = new Vector2 ( cardRect . sizeDelta . x , targetHeight ) ;
Tween . Size ( cardRect , targetSize , snapDuration , 0f , Tween . EaseOutBack ) ;
2025-11-07 01:51:03 +01:00
2025-11-07 11:24:19 +01:00
// Tween position and rotation to slot center
Tween . LocalPosition ( cardRect , Vector3 . zero , snapDuration , 0f , Tween . EaseOutBack ) ;
Tween . LocalRotation ( cardTransform , Quaternion . identity , snapDuration , 0f , Tween . EaseOutBack ,
completeCallback : ( ) = >
{
Debug . Log ( $"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}" ) ;
onComplete ? . Invoke ( ) ;
} ) ;
2025-11-07 01:51:03 +01:00
}
else
{
2025-11-07 11:24:19 +01:00
// No RectTransform, just reset and call callback
cardTransform . localPosition = Vector3 . zero ;
cardTransform . localRotation = Quaternion . identity ;
onComplete ? . Invoke ( ) ;
2025-11-07 01:51:03 +01:00
}
}
protected override void OnPointerDownHook ( )
{
base . OnPointerDownHook ( ) ;
_isHolding = true ;
// Start hold-reveal timer if card not yet revealed
if ( ! _isRevealed & & _holdRevealCoroutine = = null )
{
_holdRevealCoroutine = StartCoroutine ( HoldRevealTimer ( ) ) ;
}
}
protected override void OnPointerUpHook ( bool longPress )
{
base . OnPointerUpHook ( longPress ) ;
2025-11-07 12:51:45 +01:00
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] OnPointerUpHook on {name}, _wasDragged={_wasDragged}, _isRevealed={_isRevealed}, _waitingForPlacementTap={_waitingForPlacementTap}, longPress={longPress}" ) ;
2025-11-07 01:51:03 +01:00
_isHolding = false ;
// Cancel hold timer if running
if ( _holdRevealCoroutine ! = null )
{
2025-11-10 12:29:17 +01:00
Debug . LogWarning ( $"[PAGE-NAV-DEBUG] OnPointerUpHook - CANCELLING HoldRevealTimer coroutine! Card was released before reveal completed." ) ;
2025-11-07 01:51:03 +01:00
StopCoroutine ( _holdRevealCoroutine ) ;
_holdRevealCoroutine = null ;
}
2025-11-10 12:29:17 +01:00
else
{
Debug . Log ( $"[PAGE-NAV-DEBUG] OnPointerUpHook - No hold timer to cancel (either completed or never started)" ) ;
}
2025-11-07 01:51:03 +01:00
// Handle tap (not dragged)
if ( ! _wasDragged )
{
if ( ! _isRevealed )
{
2025-11-07 12:51:45 +01:00
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] {name} - First tap, revealing card" ) ;
2025-11-07 01:51:03 +01:00
// First tap: reveal the card
RevealCard ( ) ;
_waitingForPlacementTap = true ;
}
else if ( _waitingForPlacementTap )
{
2025-11-07 12:51:45 +01:00
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] {name} - Second tap, snapping to slot" ) ;
2025-11-07 01:51:03 +01:00
// Second tap: snap to slot
_waitingForPlacementTap = false ;
SnapToAlbumSlot ( ) ;
}
2025-11-07 12:51:45 +01:00
else
{
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] {name} - Tap after reveal but not waiting for placement tap" ) ;
}
2025-11-07 01:51:03 +01:00
}
else if ( _isDragRevealing )
{
2025-11-07 12:51:45 +01:00
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] {name} - Was drag-revealed, auto-snapping" ) ;
2025-11-07 01:51:03 +01:00
// Was drag-revealed, auto-snap on release
_isDragRevealing = false ;
SnapToAlbumSlot ( ) ;
}
2025-11-07 12:51:45 +01:00
else
{
Debug . Log ( $"[CLICK-TRACE-PLACEMENT] {name} - Was dragged but no special handling" ) ;
}
2025-11-07 01:51:03 +01:00
}
/// <summary>
/// Coroutine to reveal card after holding for specified duration
/// </summary>
private IEnumerator HoldRevealTimer ( )
{
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] HoldRevealTimer started, waiting {holdRevealDelay}s..." ) ;
2025-11-07 01:51:03 +01:00
yield return new WaitForSeconds ( holdRevealDelay ) ;
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] HoldRevealTimer completed - _isRevealed: {_isRevealed}, _isHolding: {_isHolding}" ) ;
2025-11-07 01:51:03 +01:00
// If still holding after delay, reveal the card
if ( ! _isRevealed & & _isHolding )
{
2025-11-10 12:29:17 +01:00
Debug . Log ( $"[PAGE-NAV-DEBUG] Hold timer conditions met - calling RevealCard() for zone: {(_cardData != null ? _cardData.Zone.ToString() : " NULL ")}" ) ;
2025-11-07 01:51:03 +01:00
RevealCard ( ) ;
_isDragRevealing = true ;
Debug . Log ( "[AlbumCardDraggable] Card revealed via hold" ) ;
}
2025-11-10 12:29:17 +01:00
else
{
Debug . LogWarning ( $"[PAGE-NAV-DEBUG] Hold timer completed but conditions NOT met - _isRevealed: {_isRevealed}, _isHolding: {_isHolding}. Card will NOT reveal!" ) ;
}
2025-11-07 01:51:03 +01:00
_holdRevealCoroutine = null ;
}
}
}