From 8e82c8ab2b5658ef8decbb22531d1d46fc8a500a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 23 Dec 2025 22:15:47 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- .../Blackjack/Theme/DesignConstants.swift | 29 ++++++++++++++++++- .../Views/Table/PlayerHandView.swift | 22 ++++++++------ .../Views/Table/SideBetToastView.swift | 10 +++---- .../Views/Table/SideBetZoneView.swift | 6 ++-- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/Blackjack/Blackjack/Theme/DesignConstants.swift b/Blackjack/Blackjack/Theme/DesignConstants.swift index dfa22c2..24eb15d 100644 --- a/Blackjack/Blackjack/Theme/DesignConstants.swift +++ b/Blackjack/Blackjack/Theme/DesignConstants.swift @@ -17,7 +17,7 @@ enum Design { // MARK: - Debug /// Set to true to show layout debug borders on views - static let showDebugBorders = false + static let showDebugBorders = true // MARK: - Shared Constants (from CasinoKit) @@ -71,6 +71,33 @@ enum Design { // Table static let tableHeight: CGFloat = 280 + + // Result banner + static let resultRowAmountWidth: CGFloat = 70 + static let resultRowResultWidth: CGFloat = 150 + + // Side bet zones + static let sideBetLabelFontSize: CGFloat = 13 + static let sideBetPayoutFontSize: CGFloat = 11 + + // Side bet toast notifications + static let sideBetToastTitleFontSize: CGFloat = 11 + static let sideBetToastResultFontSize: CGFloat = 12 + static let sideBetToastAmountFontSize: CGFloat = 14 + } + + // MARK: - Blackjack-Specific Delays + + enum Delay { + /// Delay before playing game over sound + static let gameOverSound: Double = 1.0 + } + + // MARK: - Blackjack-Specific Animation + + enum AnimationExtra { + /// Bounce for side bet toast animations + static let toastBounce: Double = 0.4 } } diff --git a/Blackjack/Blackjack/Views/Table/PlayerHandView.swift b/Blackjack/Blackjack/Views/Table/PlayerHandView.swift index aff1d12..1b49980 100644 --- a/Blackjack/Blackjack/Views/Table/PlayerHandView.swift +++ b/Blackjack/Blackjack/Views/Table/PlayerHandView.swift @@ -31,9 +31,9 @@ struct PlayerHandsView: View { // Display hands in reverse order (right to left play order) // Visual order: Hand 3, Hand 2, Hand 1 (left to right) // Play order: Hand 1 played first (rightmost), then Hand 2, etc. - ForEach(hands.indices.reversed(), id: \.self) { index in + ForEach(Array(hands.enumerated()).reversed(), id: \.element.id) { index, hand in PlayerHandView( - hand: hands[index], + hand: hand, isActive: index == activeHandIndex && isPlayerTurn, showCardCount: showCardCount, // Hand numbers: rightmost (index 0) is Hand 1, played first @@ -41,35 +41,39 @@ struct PlayerHandsView: View { cardWidth: cardWidth, cardSpacing: cardSpacing ) - .id(index) + .id(hand.id) + .transition(.scale.combined(with: .opacity)) } } + .animation(.spring(duration: Design.Animation.springDuration), value: hands.count) .padding(.horizontal, Design.Spacing.xxLarge) // More padding for scrolling } .scrollClipDisabled() .scrollBounceBehavior(.always) // Always allow bouncing for better scroll feel .defaultScrollAnchor(.center) // Center the content by default .onChange(of: activeHandIndex) { _, newIndex in - scrollToHand(proxy: proxy, index: newIndex) + scrollToActiveHand(proxy: proxy) } .onChange(of: totalCardCount) { _, _ in // Scroll to active hand when cards are added (hit) - scrollToHand(proxy: proxy, index: activeHandIndex) + scrollToActiveHand(proxy: proxy) } .onChange(of: hands.count) { _, _ in // Scroll to active hand when split occurs - scrollToHand(proxy: proxy, index: activeHandIndex) + scrollToActiveHand(proxy: proxy) } .onAppear { - scrollToHand(proxy: proxy, index: activeHandIndex) + scrollToActiveHand(proxy: proxy) } } .frame(maxWidth: .infinity) } - private func scrollToHand(proxy: ScrollViewProxy, index: Int) { + private func scrollToActiveHand(proxy: ScrollViewProxy) { + guard activeHandIndex < hands.count else { return } + let activeHandId = hands[activeHandIndex].id withAnimation(.easeInOut(duration: Design.Animation.quick)) { - proxy.scrollTo(index, anchor: .center) + proxy.scrollTo(activeHandId, anchor: .center) } } } diff --git a/Blackjack/Blackjack/Views/Table/SideBetToastView.swift b/Blackjack/Blackjack/Views/Table/SideBetToastView.swift index 655a8cd..7e9bfad 100644 --- a/Blackjack/Blackjack/Views/Table/SideBetToastView.swift +++ b/Blackjack/Blackjack/Views/Table/SideBetToastView.swift @@ -18,9 +18,9 @@ struct SideBetToastView: View { @State private var isShowing = false - @ScaledMetric(relativeTo: .caption) private var titleFontSize: CGFloat = 10 - @ScaledMetric(relativeTo: .caption2) private var resultFontSize: CGFloat = 11 - @ScaledMetric(relativeTo: .caption2) private var amountFontSize: CGFloat = 13 + @ScaledMetric(relativeTo: .caption) private var titleFontSize: CGFloat = Design.Size.sideBetToastTitleFontSize + @ScaledMetric(relativeTo: .callout) private var resultFontSize: CGFloat = Design.Size.sideBetToastResultFontSize + @ScaledMetric(relativeTo: .body) private var amountFontSize: CGFloat = Design.Size.sideBetToastAmountFontSize private var backgroundColor: Color { isWin ? Color.green.opacity(Design.Opacity.heavy) : Color.red.opacity(Design.Opacity.heavy) @@ -68,14 +68,14 @@ struct SideBetToastView: View { ) ) .shadow(color: borderColor.opacity(Design.Opacity.medium), radius: Design.Shadow.radiusMedium) - .scaleEffect(isShowing ? 1.0 : 0.5) + .scaleEffect(isShowing ? Design.Scale.normal : Design.Scale.shrunk) .opacity(isShowing ? 1.0 : 0) .offset(x: isShowing ? 0 : (showOnLeft ? -Design.Spacing.toastSlide : Design.Spacing.toastSlide)) .accessibilityElement(children: .combine) .accessibilityLabel("\(title): \(result)") .accessibilityValue(amountText) .onAppear { - withAnimation(.spring(duration: Design.Animation.springDuration, bounce: 0.4).delay(showOnLeft ? 0 : Design.Animation.staggerDelay1)) { + withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.AnimationExtra.toastBounce).delay(showOnLeft ? 0 : Design.Animation.staggerDelay1)) { isShowing = true } } diff --git a/Blackjack/Blackjack/Views/Table/SideBetZoneView.swift b/Blackjack/Blackjack/Views/Table/SideBetZoneView.swift index adce23c..66ad342 100644 --- a/Blackjack/Blackjack/Views/Table/SideBetZoneView.swift +++ b/Blackjack/Blackjack/Views/Table/SideBetZoneView.swift @@ -16,8 +16,8 @@ struct SideBetZoneView: View { let isAtMax: Bool let onTap: () -> Void - @ScaledMetric(relativeTo: .caption) private var labelFontSize: CGFloat = 11 - @ScaledMetric(relativeTo: .caption2) private var payoutFontSize: CGFloat = 9 + @ScaledMetric(relativeTo: .callout) private var labelFontSize: CGFloat = Design.Size.sideBetLabelFontSize + @ScaledMetric(relativeTo: .caption) private var payoutFontSize: CGFloat = Design.Size.sideBetPayoutFontSize private var backgroundColor: Color { switch betType { @@ -49,7 +49,7 @@ struct SideBetZoneView: View { RoundedRectangle(cornerRadius: Design.CornerRadius.medium) .strokeBorder( Color.white.opacity(Design.Opacity.hint), - lineWidth: Design.LineWidth.thin + lineWidth: Design.LineWidth.medium ) )