diff --git a/Blackjack/Blackjack/Views/Game/GameTableView.swift b/Blackjack/Blackjack/Views/Game/GameTableView.swift index 477eeae..1fb7f7e 100644 --- a/Blackjack/Blackjack/Views/Game/GameTableView.swift +++ b/Blackjack/Blackjack/Views/Game/GameTableView.swift @@ -22,6 +22,12 @@ struct GameTableView: View { /// Full screen size (measured from TableBackgroundView - stable, doesn't change with content) @State private var fullScreenSize: CGSize = CGSize(width: 375, height: 667) + /// Cached screen size - only updates on significant changes (orientation) + @State private var cachedScreenSize: CGSize = CGSize(width: 375, height: 667) + + /// Whether we've captured the initial screen size (only capture once) + @State private var hasInitializedScreenSize = false + // MARK: - Environment @Environment(\.horizontalSizeClass) private var horizontalSizeClass @@ -106,7 +112,32 @@ struct GameTableView: View { .onGeometryChange(for: CGSize.self) { proxy in proxy.size } action: { size in + let oldFullSize = fullScreenSize fullScreenSize = size + + // Debug: Log all geometry changes + if size != oldFullSize { + Design.debugLog("📐 Geometry changed: \(Int(oldFullSize.width))×\(Int(oldFullSize.height)) → \(Int(size.width))×\(Int(size.height))") + Design.debugLog(" Cached: \(Int(cachedScreenSize.width))×\(Int(cachedScreenSize.height)), initialized=\(hasInitializedScreenSize)") + } + + // Capture screen size ONCE on first valid measurement, then only on orientation change + if !hasInitializedScreenSize && size.width > 0 && size.height > 0 { + // First time: capture the initial size + Design.debugLog("📐 🎯 INITIAL capture: \(Int(size.width))×\(Int(size.height))") + cachedScreenSize = size + hasInitializedScreenSize = true + } else if hasInitializedScreenSize { + // After initialization: only update on TRUE orientation change + // (when portrait becomes landscape or vice versa) + let wasPortrait = cachedScreenSize.height > cachedScreenSize.width + let isPortrait = size.height > size.width + + if wasPortrait != isPortrait { + Design.debugLog("📐 🔄 ORIENTATION changed: \(Int(cachedScreenSize.width))×\(Int(cachedScreenSize.height)) → \(Int(size.width))×\(Int(size.height))") + cachedScreenSize = size + } + } } mainContent(state: state) @@ -137,14 +168,20 @@ struct GameTableView: View { .transition(.move(edge: .top).combined(with: .opacity)) } - // Table layout - fills available space + // Table layout - use fixedSize to prevent expanding when chip selector disappears + // Use cachedScreenSize to prevent card size fluctuations BlackjackTableView( state: state, selectedChip: selectedChip, - fullScreenSize: fullScreenSize + fullScreenSize: cachedScreenSize ) + .fixedSize(horizontal: false, vertical: true) .frame(maxWidth: maxContentWidth) + // Flexible spacer absorbs extra space when chip selector is hidden + // This prevents the table view from expanding/contracting + Spacer(minLength: 0) + // Chip selector - only shown during betting phase AND when result banner is NOT showing if state.currentPhase == .betting && !state.showResultBanner { ChipSelectorView( @@ -155,12 +192,6 @@ struct GameTableView: View { ) .frame(maxWidth: maxContentWidth) .debugBorder(showDebugBorders, color: .pink, label: "ChipSelector") - .onAppear { - Design.debugLog("🎰 Chip selector APPEARED (banner showing: \(state.showResultBanner))") - } - .onDisappear { - Design.debugLog("🎰 Chip selector DISAPPEARED") - } } // Action buttons - minimal spacing during player turn diff --git a/Blackjack/Blackjack/Views/Table/BlackjackTableView.swift b/Blackjack/Blackjack/Views/Table/BlackjackTableView.swift index 90ec076..9381004 100644 --- a/Blackjack/Blackjack/Views/Table/BlackjackTableView.swift +++ b/Blackjack/Blackjack/Views/Table/BlackjackTableView.swift @@ -61,19 +61,27 @@ struct BlackjackTableView: View { private var showDebugBorders: Bool { Design.showDebugBorders } var body: some View { + let currentCardWidth = cardWidth // Capture for logging + let _ = Design.debugLog("🃏 Card sizing: screenHeight=\(Int(screenHeight)), cardWidth=\(Int(currentCardWidth)), fullScreenSize=\(Int(fullScreenSize.width))×\(Int(fullScreenSize.height))") + VStack(spacing: 0) { - // Dealer area - pushed to top + // Dealer area - fixedSize prevents expanding beyond intrinsic content size DealerHandView( hand: state.dealerHand, showHoleCard: state.shouldShowDealerHoleCard, showCardCount: showCardCount, - cardWidth: cardWidth, + cardWidth: currentCardWidth, cardSpacing: cardSpacing ) + .fixedSize(horizontal: false, vertical: true) + .onGeometryChange(for: CGSize.self) { $0.size } action: { size in + Design.debugLog("📦 Dealer hand frame: \(Int(size.width))×\(Int(size.height))") + } .debugBorder(showDebugBorders, color: .red, label: "Dealer") - // Top spacer pushes dealer up + // Top spacer - limited height to prevent layout jumping Spacer(minLength: Design.Spacing.small) + .frame(maxHeight: Design.Spacing.xxLarge) .debugBorder(showDebugBorders, color: .yellow, label: "TopSpacer") // Card count view centered between dealer and player @@ -85,11 +93,13 @@ struct BlackjackTableView: View { .debugBorder(showDebugBorders, color: .mint, label: "CardCount") } - // Bottom spacer pushes player down + // Bottom spacer - limited height to prevent layout jumping Spacer(minLength: Design.Spacing.small) + .frame(maxHeight: Design.Spacing.xxLarge) .debugBorder(showDebugBorders, color: .yellow, label: "BottomSpacer") // Player hands area - only show when there are cards dealt + // fixedSize prevents the view from expanding beyond its intrinsic content size if state.playerHands.first?.cards.isEmpty == false { ZStack { PlayerHandsView( @@ -97,9 +107,10 @@ struct BlackjackTableView: View { activeHandIndex: state.activeHandIndex, isPlayerTurn: state.isPlayerTurn, showCardCount: showCardCount, - cardWidth: cardWidth, + cardWidth: currentCardWidth, cardSpacing: cardSpacing ) + .fixedSize(horizontal: false, vertical: true) // Side bet toasts (positioned on left/right sides to not cover cards) if state.settings.sideBetsEnabled && state.showSideBetToasts { @@ -160,6 +171,9 @@ struct BlackjackTableView: View { } .padding(.bottom, 5) .transition(.opacity) + .onGeometryChange(for: CGSize.self) { $0.size } action: { size in + Design.debugLog("📦 Player hands frame: \(Int(size.width))×\(Int(size.height))") + } .debugBorder(showDebugBorders, color: .green, label: "Player") } @@ -185,6 +199,9 @@ struct BlackjackTableView: View { } } .padding(.horizontal, Design.Spacing.large) + .onGeometryChange(for: CGSize.self) { $0.size } action: { size in + Design.debugLog("📦 BlackjackTableView frame: \(Int(size.width))×\(Int(size.height))") + } .debugBorder(showDebugBorders, color: .white, label: "TableView") .animation(.spring(duration: Design.Animation.springDuration), value: state.currentPhase) }