diff --git a/Baccarat/Baccarat/Theme/DesignConstants.swift b/Baccarat/Baccarat/Theme/DesignConstants.swift index 6608404..7580337 100644 --- a/Baccarat/Baccarat/Theme/DesignConstants.swift +++ b/Baccarat/Baccarat/Theme/DesignConstants.swift @@ -14,7 +14,7 @@ import CasinoKit enum Design { /// Set to true to show layout debug borders on views - static let showDebugBorders = true + static let showDebugBorders = false // MARK: - Shared Constants (from CasinoKit) diff --git a/Baccarat/Baccarat/Views/Table/CardsDisplayArea.swift b/Baccarat/Baccarat/Views/Table/CardsDisplayArea.swift index 24311e1..63999c9 100644 --- a/Baccarat/Baccarat/Views/Table/CardsDisplayArea.swift +++ b/Baccarat/Baccarat/Views/Table/CardsDisplayArea.swift @@ -20,6 +20,10 @@ struct CardsDisplayArea: View { let bankerIsWinner: Bool let isTie: Bool + // MARK: - State + + @State private var containerWidth: CGFloat = 300 + // MARK: - Environment @Environment(\.horizontalSizeClass) private var horizontalSizeClass @@ -83,21 +87,37 @@ struct CardsDisplayArea: View { return visibleCards.joined(separator: ", ") + ". " + String(format: format, bankerValue) } + /// Calculate hand section width from total container width + private var handSectionWidth: CGFloat { + (containerWidth - handsSpacing) / 2 + } + // MARK: - Body var body: some View { HStack(spacing: handsSpacing) { // Player side - playerHandSection + playerHandSection(width: handSectionWidth) .debugBorder(showDebugBorders, color: .blue, label: "Player") // Banker side - bankerHandSection + bankerHandSection(width: handSectionWidth) .debugBorder(showDebugBorders, color: .red, label: "Banker") } .frame(maxWidth: .infinity) .padding(.top, Design.Spacing.medium) .padding(.bottom, Design.Spacing.large) + .background( + GeometryReader { geometry in + Color.clear + .onAppear { + containerWidth = geometry.size.width + } + .onChange(of: geometry.size.width) { _, newWidth in + containerWidth = newWidth + } + } + ) .background( RoundedRectangle(cornerRadius: Design.CornerRadius.xLarge) .fill(Color.black.opacity(Design.Opacity.quarter)) @@ -108,7 +128,7 @@ struct CardsDisplayArea: View { // MARK: - Private Views - private var playerHandSection: some View { + private func playerHandSection(width: CGFloat) -> some View { VStack(spacing: Design.Spacing.small) { // Label with value HStack(spacing: Design.Spacing.small) { @@ -126,16 +146,17 @@ struct CardsDisplayArea: View { CompactHandView( cards: playerCards, cardsFaceUp: playerCardsFaceUp, - isWinner: playerIsWinner + isWinner: playerIsWinner, + containerWidth: width ) } - .frame(maxWidth: .infinity) + .frame(width: width) .accessibilityElement(children: .ignore) .accessibilityLabel(String(localized: "Player hand")) .accessibilityValue(playerHandDescription + (playerIsWinner ? ", " + String(localized: "Winner") : "")) } - private var bankerHandSection: some View { + private func bankerHandSection(width: CGFloat) -> some View { VStack(spacing: Design.Spacing.small) { // Label with value HStack(spacing: Design.Spacing.small) { @@ -153,10 +174,11 @@ struct CardsDisplayArea: View { CompactHandView( cards: bankerCards, cardsFaceUp: bankerCardsFaceUp, - isWinner: bankerIsWinner + isWinner: bankerIsWinner, + containerWidth: width ) } - .frame(maxWidth: .infinity) + .frame(width: width) .accessibilityElement(children: .ignore) .accessibilityLabel(String(localized: "Banker hand")) .accessibilityValue(bankerHandDescription + (bankerIsWinner ? ", " + String(localized: "Winner") : "")) diff --git a/Baccarat/Baccarat/Views/Table/CompactHandView.swift b/Baccarat/Baccarat/Views/Table/CompactHandView.swift index 0b87eeb..3282f45 100644 --- a/Baccarat/Baccarat/Views/Table/CompactHandView.swift +++ b/Baccarat/Baccarat/Views/Table/CompactHandView.swift @@ -13,6 +13,8 @@ struct CompactHandView: View { let cards: [Card] let cardsFaceUp: [Bool] let isWinner: Bool + /// Container width passed from parent for sizing + let containerWidth: CGFloat // MARK: - Environment @@ -26,9 +28,6 @@ struct CompactHandView: View { /// Maximum number of cards in baccarat hand private let maxCards: Int = 3 - /// Padding around cards - private let containerPadding: CGFloat = Design.Spacing.xSmall - /// Placeholder spacing when no cards private let placeholderSpacing: CGFloat = Design.Spacing.small @@ -44,60 +43,38 @@ struct CompactHandView: View { isLargeScreen ? 14 : 10 } - /// Calculate card width from available container width - /// Formula: containerWidth = cardWidth + (cardWidth + overlap) * 2 + padding + /// Card width calculated from container width + /// Formula: containerWidth = cardWidth + (cardWidth + overlap) * 2 /// Where overlap = cardWidth * overlapRatio - /// Solving: cardWidth = (containerWidth - 2*padding) / (1 + 2*(1 + overlapRatio)) - private func cardWidth(for containerWidth: CGFloat) -> CGFloat { - let availableWidth = containerWidth - containerPadding * 2 + private var cardWidth: CGFloat { let divisor = 1 + CGFloat(maxCards - 1) * (1 + overlapRatio) - return availableWidth / divisor + return containerWidth / divisor } /// Card overlap based on card width - private func cardOverlap(for cardWidth: CGFloat) -> CGFloat { + private var cardOverlap: CGFloat { cardWidth * overlapRatio } /// Card height based on aspect ratio - private func cardHeight(for cardWidth: CGFloat) -> CGFloat { + private var cardHeight: CGFloat { cardWidth * CasinoDesign.Size.cardAspectRatio } // MARK: - Body var body: some View { - GeometryReader { geometry in - let width = cardWidth(for: geometry.size.width) - let overlap = cardOverlap(for: width) - let height = cardHeight(for: width) - - cardsContent(cardWidth: width, cardOverlap: overlap) - .frame(width: geometry.size.width, height: height + containerPadding * 2) - .background(winnerBorder) - .overlay(alignment: .bottom) { - winBadge - } - } - .aspectRatio(contentWidth / contentHeight, contentMode: .fit) - } - - /// Aspect ratio helper - use base card dimensions for consistent sizing - private var contentWidth: CGFloat { - // Base card width for ratio calculation - let baseCardWidth: CGFloat = 45 - let baseOverlap = baseCardWidth * overlapRatio - return baseCardWidth + (baseCardWidth + baseOverlap) * CGFloat(maxCards - 1) + containerPadding * 2 - } - - private var contentHeight: CGFloat { - let baseCardWidth: CGFloat = 45 - return baseCardWidth * CasinoDesign.Size.cardAspectRatio + containerPadding * 2 + cardsContent + .frame(width: containerWidth, height: cardHeight) + .background(winnerBorder) + .overlay(alignment: .bottom) { + winBadge + } } // MARK: - Private Views - private func cardsContent(cardWidth: CGFloat, cardOverlap: CGFloat) -> some View { + private var cardsContent: some View { HStack(spacing: cards.isEmpty ? placeholderSpacing : cardOverlap) { if cards.isEmpty { // Placeholders - no overlap, just side by side @@ -152,7 +129,8 @@ struct CompactHandView: View { CompactHandView( cards: [], cardsFaceUp: [], - isWinner: false + isWinner: false, + containerWidth: 160 ) } } @@ -166,7 +144,8 @@ struct CompactHandView: View { Card(suit: .hearts, rank: .eight) ], cardsFaceUp: [true, true], - isWinner: false + isWinner: false, + containerWidth: 160 ) } } @@ -181,7 +160,8 @@ struct CompactHandView: View { Card(suit: .clubs, rank: .two) ], cardsFaceUp: [true, true, true], - isWinner: true + isWinner: true, + containerWidth: 160 ) } } @@ -195,7 +175,8 @@ struct CompactHandView: View { Card(suit: .spades, rank: .seven) ], cardsFaceUp: [false, false], - isWinner: false + isWinner: false, + containerWidth: 160 ) } }