80 lines
3.0 KiB
Swift
80 lines
3.0 KiB
Swift
//
|
|
// InteractiveCardView.swift
|
|
// Baccarat
|
|
//
|
|
// A wrapper around card views that adds interaction logic for Tap and Squeeze reveal styles.
|
|
//
|
|
|
|
import SwiftUI
|
|
import CasinoKit
|
|
|
|
struct InteractiveCardView: View {
|
|
let card: Card
|
|
let isFaceUp: Bool
|
|
let cardWidth: CGFloat
|
|
let revealStyle: RevealStyle
|
|
let isWaiting: Bool
|
|
let progress: Double
|
|
let onReveal: () -> Void
|
|
let onUpdateProgress: (Double) -> Void
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
if revealStyle == .squeeze && !isFaceUp && isWaiting {
|
|
// Specialized squeeze view
|
|
SqueezeCardView(card: card, width: cardWidth, progress: progress)
|
|
.contentShape(Rectangle())
|
|
.gesture(
|
|
DragGesture(minimumDistance: 0)
|
|
.onChanged { value in
|
|
let dx = abs(value.translation.width)
|
|
let dy = abs(value.translation.height)
|
|
let distance = sqrt(dx*dx + dy*dy)
|
|
let maxDistance = cardWidth * 1.0
|
|
let newProgress = min(1.0, max(progress, Double(distance / maxDistance)))
|
|
onUpdateProgress(newProgress)
|
|
}
|
|
)
|
|
.overlay {
|
|
if progress < 0.05 {
|
|
revealInstructionOverlay(text: String(localized: "PEEL"))
|
|
}
|
|
}
|
|
} else {
|
|
// Standard CardView (handles its own flip animation)
|
|
CardView(card: card, isFaceUp: isFaceUp, cardWidth: cardWidth)
|
|
.overlay {
|
|
if !isFaceUp && isWaiting && revealStyle == .tap {
|
|
revealInstructionOverlay(text: String(localized: "TAP"))
|
|
}
|
|
}
|
|
.onTapGesture {
|
|
if !isFaceUp && isWaiting && revealStyle == .tap {
|
|
onReveal()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func revealInstructionOverlay(text: String) -> some View {
|
|
Text(text)
|
|
.font(.system(size: Design.BaseFontSize.small, weight: .black, design: .rounded))
|
|
.foregroundStyle(.white)
|
|
.padding(.horizontal, Design.Spacing.small)
|
|
.padding(.vertical, Design.Spacing.xxSmall)
|
|
.background(
|
|
Capsule()
|
|
.fill(Color.black.opacity(Design.Opacity.heavy))
|
|
.overlay(
|
|
Capsule()
|
|
.strokeBorder(.white.opacity(Design.Opacity.medium), lineWidth: 1)
|
|
)
|
|
)
|
|
.scaleEffect(isWaiting ? 1.0 : 0.8)
|
|
.opacity(isWaiting ? 1.0 : 0)
|
|
.animation(.interactiveSpring().repeatForever(), value: isWaiting)
|
|
.allowsHitTesting(false)
|
|
}
|
|
}
|