1st attempt of roation
Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
8c35899c38
commit
fa016047c2
@ -518,6 +518,13 @@ final class GameState {
|
|||||||
return bet.amount < minBet
|
return bet.amount < minBet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which main bet is placed - nil if no main bet, true if Player, false if Banker.
|
||||||
|
/// Used to determine card layout ordering (betted hand appears on bottom).
|
||||||
|
var bettedOnPlayer: Bool? {
|
||||||
|
guard let bet = mainBet else { return nil }
|
||||||
|
return bet.type == .player
|
||||||
|
}
|
||||||
|
|
||||||
/// Amount needed to reach the minimum bet.
|
/// Amount needed to reach the minimum bet.
|
||||||
var amountNeededForMinimum: Int {
|
var amountNeededForMinimum: Int {
|
||||||
guard let bet = mainBet else { return minBet }
|
guard let bet = mainBet else { return minBet }
|
||||||
|
|||||||
@ -37,21 +37,11 @@ struct GameTableView: View {
|
|||||||
isLandscape ? Design.Spacing.medium : Design.Spacing.xSmall
|
isLandscape ? Design.Spacing.medium : Design.Spacing.xSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Minimum spacer height - smaller in landscape to fit content
|
|
||||||
private var minSpacerHeight: CGFloat {
|
|
||||||
isLandscape ? 0 : Design.Spacing.xSmall
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Smaller spacer height - reduced in landscape
|
/// Smaller spacer height - reduced in landscape
|
||||||
private var smallSpacerHeight: CGFloat {
|
private var smallSpacerHeight: CGFloat {
|
||||||
isLandscape ? Design.Spacing.xxSmall : Design.Spacing.small
|
isLandscape ? Design.Spacing.xxSmall : Design.Spacing.small
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Medium spacer height - reduced in landscape
|
|
||||||
private var mediumSpacerHeight: CGFloat {
|
|
||||||
isLandscape ? Design.Spacing.xSmall : Design.Spacing.medium
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maximum width for game content on large screens
|
/// Maximum width for game content on large screens
|
||||||
private var maxContentWidth: CGFloat {
|
private var maxContentWidth: CGFloat {
|
||||||
isLandscape ? CasinoDesign.Size.maxContentWidthLandscape : CasinoDesign.Size.maxContentWidthPortrait
|
isLandscape ? CasinoDesign.Size.maxContentWidthLandscape : CasinoDesign.Size.maxContentWidthPortrait
|
||||||
@ -73,6 +63,11 @@ struct GameTableView: View {
|
|||||||
state.lastResult == .tie
|
state.lastResult == .tie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether we're in a dealing/result phase (vertical layout) vs betting phase (horizontal)
|
||||||
|
private var isDealing: Bool {
|
||||||
|
state.currentPhase != .betting
|
||||||
|
}
|
||||||
|
|
||||||
// Use global debug flag from Design constants
|
// Use global debug flag from Design constants
|
||||||
private var showDebugBorders: Bool { Design.showDebugBorders }
|
private var showDebugBorders: Bool { Design.showDebugBorders }
|
||||||
|
|
||||||
@ -195,7 +190,9 @@ struct GameTableView: View {
|
|||||||
bankerIsWinner: bankerIsWinner,
|
bankerIsWinner: bankerIsWinner,
|
||||||
isTie: isTie,
|
isTie: isTie,
|
||||||
showAnimations: settings.showAnimations,
|
showAnimations: settings.showAnimations,
|
||||||
dealingSpeed: settings.dealingSpeed
|
dealingSpeed: settings.dealingSpeed,
|
||||||
|
bettedOnPlayer: state.bettedOnPlayer,
|
||||||
|
isDealing: isDealing
|
||||||
)
|
)
|
||||||
.frame(maxWidth: maxContentWidth)
|
.frame(maxWidth: maxContentWidth)
|
||||||
.padding(.horizontal, Design.Spacing.medium)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
@ -264,7 +261,7 @@ struct GameTableView: View {
|
|||||||
.safeAreaPadding(.bottom, Design.Spacing.small)
|
.safeAreaPadding(.bottom, Design.Spacing.small)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Portrait layout with RoadMap inline
|
/// Portrait layout - vertical card layout, no RoadMap (shown only in landscape)
|
||||||
private var portraitLayout: some View {
|
private var portraitLayout: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
// Top bar with balance and info (from CasinoKit)
|
// Top bar with balance and info (from CasinoKit)
|
||||||
@ -278,7 +275,7 @@ struct GameTableView: View {
|
|||||||
)
|
)
|
||||||
.debugBorder(showDebugBorders, color: .cyan, label: "TopBar")
|
.debugBorder(showDebugBorders, color: .cyan, label: "TopBar")
|
||||||
|
|
||||||
// Cards display area
|
// Cards display area - animates from horizontal to vertical when dealing
|
||||||
CardsDisplayArea(
|
CardsDisplayArea(
|
||||||
playerCards: state.visiblePlayerCards,
|
playerCards: state.visiblePlayerCards,
|
||||||
bankerCards: state.visibleBankerCards,
|
bankerCards: state.visibleBankerCards,
|
||||||
@ -290,25 +287,16 @@ struct GameTableView: View {
|
|||||||
bankerIsWinner: bankerIsWinner,
|
bankerIsWinner: bankerIsWinner,
|
||||||
isTie: isTie,
|
isTie: isTie,
|
||||||
showAnimations: settings.showAnimations,
|
showAnimations: settings.showAnimations,
|
||||||
dealingSpeed: settings.dealingSpeed
|
dealingSpeed: settings.dealingSpeed,
|
||||||
|
bettedOnPlayer: state.bettedOnPlayer,
|
||||||
|
isDealing: isDealing
|
||||||
)
|
)
|
||||||
.frame(maxWidth: isLargeScreen ? maxContentWidth : .infinity)
|
.frame(maxWidth: isLargeScreen ? maxContentWidth : .infinity)
|
||||||
.padding(.horizontal, Design.Spacing.medium)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
.debugBorder(showDebugBorders, color: .red, label: "CardsArea")
|
.debugBorder(showDebugBorders, color: .red, label: "CardsArea")
|
||||||
|
|
||||||
Spacer(minLength: minSpacerHeight)
|
|
||||||
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer2")
|
|
||||||
|
|
||||||
// Road map history
|
|
||||||
if settings.showHistory {
|
|
||||||
RoadMapView(results: state.recentResults)
|
|
||||||
.frame(maxWidth: isLargeScreen ? maxContentWidth : .infinity)
|
|
||||||
.padding(.horizontal, Design.Spacing.medium)
|
|
||||||
.debugBorder(showDebugBorders, color: .orange, label: "RoadMap")
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(minLength: smallSpacerHeight)
|
Spacer(minLength: smallSpacerHeight)
|
||||||
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer3")
|
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer2")
|
||||||
|
|
||||||
// Betting table
|
// Betting table
|
||||||
BettingTableView(
|
BettingTableView(
|
||||||
|
|||||||
@ -3,12 +3,16 @@
|
|||||||
// Baccarat
|
// Baccarat
|
||||||
//
|
//
|
||||||
// The cards display area showing both Player and Banker hands.
|
// The cards display area showing both Player and Banker hands.
|
||||||
|
// Defaults to side-by-side during betting, animates to vertical during dealing
|
||||||
|
// with the betted hand on bottom.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import CasinoKit
|
import CasinoKit
|
||||||
|
|
||||||
/// The cards display area showing both hands.
|
/// The cards display area showing both hands.
|
||||||
|
/// - Betting phase: Horizontal side-by-side layout (Player | Banker)
|
||||||
|
/// - Dealing/Result phases: Vertical layout with betted hand on bottom
|
||||||
struct CardsDisplayArea: View {
|
struct CardsDisplayArea: View {
|
||||||
let playerCards: [Card]
|
let playerCards: [Card]
|
||||||
let bankerCards: [Card]
|
let bankerCards: [Card]
|
||||||
@ -21,6 +25,11 @@ struct CardsDisplayArea: View {
|
|||||||
let isTie: Bool
|
let isTie: Bool
|
||||||
let showAnimations: Bool
|
let showAnimations: Bool
|
||||||
let dealingSpeed: Double
|
let dealingSpeed: Double
|
||||||
|
/// Which main bet is placed - nil if no main bet, true if Player, false if Banker.
|
||||||
|
/// Determines layout ordering in vertical mode: betted hand appears on bottom.
|
||||||
|
let bettedOnPlayer: Bool?
|
||||||
|
/// Whether the game is in dealing/result phase (vertical layout) or betting phase (horizontal).
|
||||||
|
let isDealing: Bool
|
||||||
|
|
||||||
// MARK: - State
|
// MARK: - State
|
||||||
|
|
||||||
@ -50,9 +59,22 @@ struct CardsDisplayArea: View {
|
|||||||
isLargeScreen ? 40 : Design.Size.labelRowHeight
|
isLargeScreen ? 40 : Design.Size.labelRowHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spacing between PLAYER and BANKER hands - reduced on smaller screens
|
/// Spacing between hands
|
||||||
private var handsSpacing: CGFloat {
|
private var handsSpacing: CGFloat {
|
||||||
isLargeScreen ? Design.Spacing.xxxLarge : Design.Spacing.large
|
if isDealing {
|
||||||
|
return isLargeScreen ? Design.Spacing.large : Design.Spacing.medium
|
||||||
|
} else {
|
||||||
|
return isLargeScreen ? Design.Spacing.xxxLarge : Design.Spacing.large
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Card section width - larger in vertical mode (more horizontal space)
|
||||||
|
private var handSectionWidth: CGFloat {
|
||||||
|
if isDealing {
|
||||||
|
return containerWidth * 0.7
|
||||||
|
} else {
|
||||||
|
return (containerWidth - handsSpacing) / 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Accessibility
|
// MARK: - Accessibility
|
||||||
@ -89,22 +111,50 @@ struct CardsDisplayArea: View {
|
|||||||
return visibleCards.joined(separator: ", ") + ". " + String(format: format, bankerValue)
|
return visibleCards.joined(separator: ", ") + ". " + String(format: format, bankerValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate hand section width from total container width
|
/// Whether Player hand should be on bottom (true) or top (false) in vertical mode.
|
||||||
private var handSectionWidth: CGFloat {
|
/// Defaults to Player on bottom if no bet placed.
|
||||||
(containerWidth - handsSpacing) / 2
|
private var playerOnBottom: Bool {
|
||||||
|
bettedOnPlayer ?? true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The layout to use - HStack for horizontal, VStack for vertical
|
||||||
|
private var layout: AnyLayout {
|
||||||
|
isDealing ? AnyLayout(VStackLayout(spacing: handsSpacing)) : AnyLayout(HStackLayout(spacing: handsSpacing))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Body
|
// MARK: - Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: handsSpacing) {
|
layout {
|
||||||
// Player side
|
// First position: Player in horizontal, or top hand in vertical
|
||||||
|
if isDealing && !playerOnBottom {
|
||||||
|
// Vertical mode, player on top
|
||||||
playerHandSection(width: handSectionWidth)
|
playerHandSection(width: handSectionWidth)
|
||||||
.debugBorder(showDebugBorders, color: .blue, label: "Player")
|
.debugBorder(showDebugBorders, color: .blue, label: "Player")
|
||||||
|
} else if isDealing && playerOnBottom {
|
||||||
// Banker side
|
// Vertical mode, banker on top
|
||||||
bankerHandSection(width: handSectionWidth)
|
bankerHandSection(width: handSectionWidth)
|
||||||
.debugBorder(showDebugBorders, color: .red, label: "Banker")
|
.debugBorder(showDebugBorders, color: .red, label: "Banker")
|
||||||
|
} else {
|
||||||
|
// Horizontal mode - player always on left
|
||||||
|
playerHandSection(width: handSectionWidth)
|
||||||
|
.debugBorder(showDebugBorders, color: .blue, label: "Player")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second position: Banker in horizontal, or bottom hand in vertical
|
||||||
|
if isDealing && !playerOnBottom {
|
||||||
|
// Vertical mode, banker on bottom
|
||||||
|
bankerHandSection(width: handSectionWidth)
|
||||||
|
.debugBorder(showDebugBorders, color: .red, label: "Banker")
|
||||||
|
} else if isDealing && playerOnBottom {
|
||||||
|
// Vertical mode, player on bottom
|
||||||
|
playerHandSection(width: handSectionWidth)
|
||||||
|
.debugBorder(showDebugBorders, color: .blue, label: "Player")
|
||||||
|
} else {
|
||||||
|
// Horizontal mode - banker always on right
|
||||||
|
bankerHandSection(width: handSectionWidth)
|
||||||
|
.debugBorder(showDebugBorders, color: .red, label: "Banker")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.top, Design.Spacing.medium)
|
.padding(.top, Design.Spacing.medium)
|
||||||
@ -126,6 +176,8 @@ struct CardsDisplayArea: View {
|
|||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
)
|
)
|
||||||
.debugBorder(showDebugBorders, color: .mint, label: "HandsContainer")
|
.debugBorder(showDebugBorders, color: .mint, label: "HandsContainer")
|
||||||
|
.animation(.spring(duration: 0.5, bounce: 0.2), value: isDealing)
|
||||||
|
.animation(.spring(duration: 0.4, bounce: 0.15), value: playerOnBottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private Views
|
// MARK: - Private Views
|
||||||
@ -193,7 +245,7 @@ struct CardsDisplayArea: View {
|
|||||||
|
|
||||||
// MARK: - Previews
|
// MARK: - Previews
|
||||||
|
|
||||||
#Preview("Empty Hands") {
|
#Preview("Horizontal - Betting Phase") {
|
||||||
ZStack {
|
ZStack {
|
||||||
TableBackgroundView()
|
TableBackgroundView()
|
||||||
CardsDisplayArea(
|
CardsDisplayArea(
|
||||||
@ -207,12 +259,14 @@ struct CardsDisplayArea: View {
|
|||||||
bankerIsWinner: false,
|
bankerIsWinner: false,
|
||||||
isTie: false,
|
isTie: false,
|
||||||
showAnimations: true,
|
showAnimations: true,
|
||||||
dealingSpeed: 1.0
|
dealingSpeed: 1.0,
|
||||||
|
bettedOnPlayer: nil,
|
||||||
|
isDealing: false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview("Player Wins") {
|
#Preview("Vertical - Dealing (Bet on Player)") {
|
||||||
ZStack {
|
ZStack {
|
||||||
TableBackgroundView()
|
TableBackgroundView()
|
||||||
CardsDisplayArea(
|
CardsDisplayArea(
|
||||||
@ -232,12 +286,14 @@ struct CardsDisplayArea: View {
|
|||||||
bankerIsWinner: false,
|
bankerIsWinner: false,
|
||||||
isTie: false,
|
isTie: false,
|
||||||
showAnimations: true,
|
showAnimations: true,
|
||||||
dealingSpeed: 1.0
|
dealingSpeed: 1.0,
|
||||||
|
bettedOnPlayer: true,
|
||||||
|
isDealing: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview("Banker Wins with 3 Cards") {
|
#Preview("Vertical - Dealing (Bet on Banker)") {
|
||||||
ZStack {
|
ZStack {
|
||||||
TableBackgroundView()
|
TableBackgroundView()
|
||||||
CardsDisplayArea(
|
CardsDisplayArea(
|
||||||
@ -254,13 +310,14 @@ struct CardsDisplayArea: View {
|
|||||||
playerCardsFaceUp: [true, true, true],
|
playerCardsFaceUp: [true, true, true],
|
||||||
bankerCardsFaceUp: [true, true, true],
|
bankerCardsFaceUp: [true, true, true],
|
||||||
playerValue: 9,
|
playerValue: 9,
|
||||||
bankerValue: 8,
|
bankerValue: 9,
|
||||||
playerIsWinner: false,
|
playerIsWinner: false,
|
||||||
bankerIsWinner: true,
|
bankerIsWinner: true,
|
||||||
isTie: false,
|
isTie: false,
|
||||||
showAnimations: true,
|
showAnimations: true,
|
||||||
dealingSpeed: 1.0
|
dealingSpeed: 1.0,
|
||||||
|
bettedOnPlayer: false,
|
||||||
|
isDealing: true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ enum Design {
|
|||||||
// MARK: - Debug
|
// MARK: - Debug
|
||||||
|
|
||||||
/// Set to true to show layout debug borders on views
|
/// Set to true to show layout debug borders on views
|
||||||
static let showDebugBorders = true
|
static let showDebugBorders = false
|
||||||
|
|
||||||
/// Set to true to show debug log statements
|
/// Set to true to show debug log statements
|
||||||
static let showDebugLogs = false
|
static let showDebugLogs = false
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user