2025-11-07 01:51:03 +01:00
using System ;
using System.Collections ;
using AppleHills.Data.CardSystem ;
2025-11-10 13:03:36 +01:00
using Core ;
2025-11-07 01:51:03 +01:00
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
if ( _isRevealed )
{
return ;
}
2025-11-07 01:51:03 +01:00
_isRevealed = true ;
if ( flippableCard ! = null )
{
flippableCard . FlipToReveal ( ) ;
}
OnCardRevealed ? . Invoke ( this , _cardData ) ;
}
/// <summary>
/// Snap to the matching album slot
/// </summary>
public void SnapToAlbumSlot ( )
{
if ( _cardData = = null )
{
2025-11-10 13:03:36 +01:00
Logging . Warning ( "[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
2025-11-10 13:03:36 +01:00
Logging . Debug ( $"[AlbumCardPlacementDraggable] Card placement animation complete for {_cardData.Name}" ) ;
2025-11-07 11:24:19 +01:00
// Notify that card was placed
OnCardPlacedInAlbum ? . Invoke ( this , _cardData ) ;
// Destroy this wrapper (the AlbumPlacementCard)
Destroy ( gameObject ) ;
} ) ;
}
else
{
2025-11-10 13:03:36 +01:00
Logging . Warning ( "[AlbumCardPlacementDraggable] Failed to extract AlbumCard from wrapper!" ) ;
2025-11-07 11:24:19 +01:00
}
}
}
else
{
2025-11-10 13:03:36 +01:00
Logging . Warning ( $"[AlbumCardPlacementDraggable] Could not find matching slot for card '{_cardData.Name}' (Zone: {_cardData.Zone}, Index: {_cardData.CollectionIndex})" ) ;
2025-11-07 11:24:19 +01:00
}
}
/// <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 : ( ) = >
{
2025-11-10 13:03:36 +01:00
Logging . Debug ( $"[AlbumCardPlacementDraggable] Tween complete for extracted card {card.name}, final height: {cardRect.sizeDelta.y}" ) ;
2025-11-07 11:24:19 +01:00
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 ) ;
_isHolding = false ;
// Cancel hold timer if running
if ( _holdRevealCoroutine ! = null )
{
StopCoroutine ( _holdRevealCoroutine ) ;
_holdRevealCoroutine = null ;
}
2025-11-10 12:29:17 +01:00
else
{
}
2025-11-07 01:51:03 +01:00
// Handle tap (not dragged)
if ( ! _wasDragged )
{
if ( ! _isRevealed )
{
// First tap: reveal the card
RevealCard ( ) ;
_waitingForPlacementTap = true ;
}
else if ( _waitingForPlacementTap )
{
// Second tap: snap to slot
_waitingForPlacementTap = false ;
SnapToAlbumSlot ( ) ;
}
2025-11-07 12:51:45 +01:00
else
{
}
2025-11-07 01:51:03 +01:00
}
else if ( _isDragRevealing )
{
// Was drag-revealed, auto-snap on release
_isDragRevealing = false ;
SnapToAlbumSlot ( ) ;
}
}
/// <summary>
/// Coroutine to reveal card after holding for specified duration
/// </summary>
private IEnumerator HoldRevealTimer ( )
{
yield return new WaitForSeconds ( holdRevealDelay ) ;
// If still holding after delay, reveal the card
if ( ! _isRevealed & & _isHolding )
{
RevealCard ( ) ;
_isDragRevealing = true ;
2025-11-10 12:29:17 +01:00
}
2025-11-07 01:51:03 +01:00
_holdRevealCoroutine = null ;
}
}
}