Signed-off-by: Matt Bruce <matt.bruce1@toyota.com>

This commit is contained in:
Matt Bruce 2025-12-23 22:18:21 -06:00
parent 8cbd85dcce
commit 34455378fc
3 changed files with 93 additions and 43 deletions

View File

@ -35,10 +35,8 @@ struct ActionButtonsView: View {
EmptyView()
}
}
.animation(.spring(duration: Design.Animation.quick), value: state.currentPhase)
.animation(.easeInOut(duration: Design.Animation.standard), value: state.currentBet > 0)
}
.frame(minHeight: containerHeight)
.frame(height: containerHeight)
.padding(.horizontal, Design.Spacing.large)
}

View File

@ -130,20 +130,22 @@ struct GameTableView: View {
)
.frame(maxWidth: maxContentWidth)
// Chip selector - only shown during betting phase
if state.currentPhase == .betting {
Spacer()
.debugBorder(showDebugBorders, color: .yellow, label: "ChipSpacer")
// Chip selector - only shown during betting phase AND when result banner is NOT showing
if state.currentPhase == .betting && !state.showResultBanner {
ChipSelectorView(
selectedChip: $selectedChip,
balance: state.balance,
currentBet: state.minBetForChipSelector, // Use min bet so chips stay enabled if any bet type can accept more
currentBet: state.minBetForChipSelector,
maxBet: state.settings.maxBet
)
.frame(maxWidth: maxContentWidth)
.transition(.opacity.combined(with: .move(edge: .bottom)))
.debugBorder(showDebugBorders, color: .pink, label: "ChipSelector")
.onAppear {
print("🎰 Chip selector APPEARED (banner showing: \(state.showResultBanner))")
}
.onDisappear {
print("🎰 Chip selector DISAPPEARED")
}
}
// Action buttons - minimal spacing during player turn
@ -152,43 +154,78 @@ struct GameTableView: View {
.padding(.bottom, Design.Spacing.small)
.debugBorder(showDebugBorders, color: .blue, label: "ActionBtns")
}
.frame(maxWidth: .infinity)
.frame(maxWidth: .infinity, alignment: .top)
.zIndex(1)
.onChange(of: state.currentPhase) { oldPhase, newPhase in
print("🔄 Phase changed: \(oldPhase)\(newPhase)")
}
// Insurance popup overlay (covers entire screen)
if state.currentPhase == .insurance {
InsurancePopupView(
betAmount: state.currentBet / 2,
balance: state.balance,
onTake: { Task { await state.takeInsurance() } },
onDecline: { state.declineInsurance() }
)
.transition(.opacity.combined(with: .scale(scale: 0.9)))
Color.clear
.overlay(alignment: .center) {
InsurancePopupView(
betAmount: state.currentBet / 2,
balance: state.balance,
onTake: { Task { await state.takeInsurance() } },
onDecline: { state.declineInsurance() }
)
}
.ignoresSafeArea()
.allowsHitTesting(true)
.transition(.opacity.combined(with: .scale(scale: 0.9)))
.zIndex(100)
}
// Result banner overlay
if state.showResultBanner, let result = state.lastRoundResult {
ResultBannerView(
result: result,
currentBalance: state.balance,
minBet: state.settings.minBet,
onNewRound: { state.newRound() },
onPlayAgain: { state.resetGame() }
)
Color.clear
.overlay(alignment: .center) {
ResultBannerView(
result: result,
currentBalance: state.balance,
minBet: state.settings.minBet,
onNewRound: { state.newRound() },
onPlayAgain: { state.resetGame() }
)
.onAppear {
print("🎯 RESULT BANNER APPEARED")
}
.onDisappear {
print("❌ RESULT BANNER DISAPPEARED")
}
}
.ignoresSafeArea()
.allowsHitTesting(true)
.zIndex(100)
}
// Confetti for wins (matching Baccarat pattern)
if state.showResultBanner && (state.lastRoundResult?.totalWinnings ?? 0) > 0 {
ConfettiView()
.zIndex(101)
}
// Game over
if state.isGameOver && !state.showResultBanner {
GameOverView(
roundsPlayed: state.roundsPlayed,
onPlayAgain: { state.resetGame() }
)
Color.clear
.overlay(alignment: .center) {
GameOverView(
roundsPlayed: state.roundsPlayed,
onPlayAgain: { state.resetGame() }
)
}
.ignoresSafeArea()
.allowsHitTesting(true)
.zIndex(100)
}
}
.onChange(of: state.playerHands.count) { oldCount, newCount in
print("👥 Player hands count: \(oldCount)\(newCount)")
}
.onChange(of: state.balance) { oldBalance, newBalance in
print("💰 Balance: \(oldBalance)\(newBalance)")
}
}
}

View File

@ -54,7 +54,6 @@ struct ResultBannerView: View {
ZStack {
// Full screen dark background
Color.black.opacity(Design.Opacity.strong)
.ignoresSafeArea()
// Content card
VStack(spacing: Design.Spacing.xLarge) {
@ -193,18 +192,18 @@ struct ResultBannerView: View {
.shadow(color: mainResultColor.opacity(Design.Opacity.hint), radius: Design.Shadow.radiusXLarge)
.frame(maxWidth: CasinoDesign.Size.maxModalWidth)
.padding(.horizontal, Design.Spacing.large) // Prevent clipping on sides
.scaleEffect(showContent ? 1.0 : 0.8)
.scaleEffect(showContent ? Design.Scale.normal : Design.Scale.slightShrink)
.opacity(showContent ? 1.0 : 0)
}
.onAppear {
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: 0.3)) {
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce)) {
showContent = true
}
// Play game over sound if out of chips (after a delay so it doesn't overlap with result sound)
if isGameOver {
Task {
try? await Task.sleep(for: .seconds(1))
try? await Task.sleep(for: .seconds(Design.Delay.gameOverSound))
SoundManager.shared.play(.gameOver)
}
}
@ -222,6 +221,8 @@ struct ResultRow: View {
let result: HandResult
var amount: Int? = nil
private var showDebugBorders: Bool { Design.showDebugBorders }
private var amountText: String? {
guard let amount = amount else { return nil }
if amount > 0 {
@ -243,24 +244,31 @@ struct ResultRow: View {
var body: some View {
HStack {
Text(label)
.font(.system(size: Design.BaseFontSize.body))
.font(.system(size: Design.BaseFontSize.medium))
.foregroundStyle(.white.opacity(Design.Opacity.strong))
.debugBorder(showDebugBorders, color: .blue, label: "Label")
Spacer()
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer")
// Show amount if provided
if let amountText = amountText {
Text(amountText)
.font(.system(size: Design.BaseFontSize.body, weight: .semibold, design: .rounded))
.font(.system(size: Design.BaseFontSize.medium, weight: .semibold, design: .rounded))
.foregroundStyle(amountColor)
.frame(width: 70, alignment: .trailing)
.frame(width: Design.Size.resultRowAmountWidth, alignment: .trailing)
.debugBorder(showDebugBorders, color: .green, label: "Amount")
}
Text(result.displayText)
.font(.system(size: Design.BaseFontSize.body, weight: .bold))
.font(.system(size: Design.BaseFontSize.large, weight: .bold))
.foregroundStyle(result.color)
.frame(width: 100, alignment: .trailing)
.frame(width: Design.Size.resultRowResultWidth, alignment: .trailing)
.lineLimit(1)
.minimumScaleFactor(Design.MinScaleFactor.comfortable)
.debugBorder(showDebugBorders, color: .red, label: "Result")
}
.debugBorder(showDebugBorders, color: .white, label: "ResultRow")
}
}
@ -272,6 +280,8 @@ struct SideBetResultRow: View {
let isWin: Bool
let amount: Int
private var showDebugBorders: Bool { Design.showDebugBorders }
private var amountText: String {
if amount > 0 {
return "+$\(amount)"
@ -295,23 +305,28 @@ struct SideBetResultRow: View {
var body: some View {
HStack {
Text(label)
.font(.system(size: Design.BaseFontSize.body))
.font(.system(size: Design.BaseFontSize.medium))
.foregroundStyle(.white.opacity(Design.Opacity.strong))
.debugBorder(showDebugBorders, color: .blue, label: "Label")
Spacer()
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer")
Text(amountText)
.font(.system(size: Design.BaseFontSize.body, weight: .semibold, design: .rounded))
.font(.system(size: Design.BaseFontSize.medium, weight: .semibold, design: .rounded))
.foregroundStyle(amountColor)
.frame(width: 70, alignment: .trailing)
.frame(width: Design.Size.resultRowAmountWidth, alignment: .trailing)
.debugBorder(showDebugBorders, color: .green, label: "Amount")
Text(resultText)
.font(.system(size: Design.BaseFontSize.body, weight: .bold))
.font(.system(size: Design.BaseFontSize.large, weight: .bold))
.foregroundStyle(resultColor)
.frame(width: 100, alignment: .trailing)
.frame(width: Design.Size.resultRowResultWidth, alignment: .trailing)
.lineLimit(1)
.minimumScaleFactor(Design.MinScaleFactor.comfortable)
.debugBorder(showDebugBorders, color: .red, label: "Result")
}
.debugBorder(showDebugBorders, color: .white, label: "SideBetRow")
}
}