Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
889e91a8ca
commit
98d72d0db8
@ -485,7 +485,11 @@ final class GameState {
|
|||||||
evaluateSideBets()
|
evaluateSideBets()
|
||||||
|
|
||||||
// Check for insurance offer (only in American style with hole card)
|
// Check for insurance offer (only in American style with hole card)
|
||||||
if !settings.noHoleCard, let upCard = dealerUpCard, engine.shouldOfferInsurance(dealerUpCard: upCard) {
|
// Skip if user has opted out of insurance prompts
|
||||||
|
if !settings.noHoleCard,
|
||||||
|
!settings.neverAskInsurance,
|
||||||
|
let upCard = dealerUpCard,
|
||||||
|
engine.shouldOfferInsurance(dealerUpCard: upCard) {
|
||||||
currentPhase = .insurance
|
currentPhase = .insurance
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -567,6 +571,12 @@ final class GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declines insurance and sets the "never ask again" preference.
|
||||||
|
func neverAskInsurance() {
|
||||||
|
settings.neverAskInsurance = true
|
||||||
|
declineInsurance()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Player Actions
|
// MARK: - Player Actions
|
||||||
|
|
||||||
/// Player hits (takes another card).
|
/// Player hits (takes another card).
|
||||||
|
|||||||
@ -105,6 +105,9 @@ final class GameSettings {
|
|||||||
/// Whether insurance is offered.
|
/// Whether insurance is offered.
|
||||||
var insuranceAllowed: Bool = true { didSet { save() } }
|
var insuranceAllowed: Bool = true { didSet { save() } }
|
||||||
|
|
||||||
|
/// Whether to skip the insurance prompt and auto-decline.
|
||||||
|
var neverAskInsurance: Bool = false { didSet { save() } }
|
||||||
|
|
||||||
/// Blackjack payout ratio (1.5 = 3:2, 1.2 = 6:5)
|
/// Blackjack payout ratio (1.5 = 3:2, 1.2 = 6:5)
|
||||||
var blackjackPayout: Double = 1.5 { didSet { save() } }
|
var blackjackPayout: Double = 1.5 { didSet { save() } }
|
||||||
|
|
||||||
@ -237,6 +240,7 @@ final class GameSettings {
|
|||||||
self.noHoleCard = data.noHoleCard
|
self.noHoleCard = data.noHoleCard
|
||||||
self.blackjackPayout = data.blackjackPayout
|
self.blackjackPayout = data.blackjackPayout
|
||||||
self.insuranceAllowed = data.insuranceAllowed
|
self.insuranceAllowed = data.insuranceAllowed
|
||||||
|
self.neverAskInsurance = data.neverAskInsurance
|
||||||
self.sideBetsEnabled = data.sideBetsEnabled
|
self.sideBetsEnabled = data.sideBetsEnabled
|
||||||
self.showAnimations = data.showAnimations
|
self.showAnimations = data.showAnimations
|
||||||
self.dealingSpeed = data.dealingSpeed
|
self.dealingSpeed = data.dealingSpeed
|
||||||
@ -263,6 +267,7 @@ final class GameSettings {
|
|||||||
noHoleCard: noHoleCard,
|
noHoleCard: noHoleCard,
|
||||||
blackjackPayout: blackjackPayout,
|
blackjackPayout: blackjackPayout,
|
||||||
insuranceAllowed: insuranceAllowed,
|
insuranceAllowed: insuranceAllowed,
|
||||||
|
neverAskInsurance: neverAskInsurance,
|
||||||
sideBetsEnabled: sideBetsEnabled,
|
sideBetsEnabled: sideBetsEnabled,
|
||||||
showAnimations: showAnimations,
|
showAnimations: showAnimations,
|
||||||
dealingSpeed: dealingSpeed,
|
dealingSpeed: dealingSpeed,
|
||||||
@ -290,6 +295,7 @@ final class GameSettings {
|
|||||||
noHoleCard = false
|
noHoleCard = false
|
||||||
blackjackPayout = 1.5
|
blackjackPayout = 1.5
|
||||||
insuranceAllowed = true
|
insuranceAllowed = true
|
||||||
|
neverAskInsurance = false
|
||||||
sideBetsEnabled = false
|
sideBetsEnabled = false
|
||||||
showAnimations = true
|
showAnimations = true
|
||||||
dealingSpeed = 1.0
|
dealingSpeed = 1.0
|
||||||
|
|||||||
@ -1057,6 +1057,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Auto-decline when dealer shows Ace" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Auto-decline when dealer shows Ace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"es-MX" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Rechazar automáticamente cuando el crupier muestra As"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr-CA" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Refuser automatiquement quand le croupier montre un As"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Baccarat" : {
|
"Baccarat" : {
|
||||||
"comment" : "The name of a casino game.",
|
"comment" : "The name of a casino game.",
|
||||||
"isCommentAutoGenerated" : true,
|
"isCommentAutoGenerated" : true,
|
||||||
@ -2625,6 +2647,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Don't Ask" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Don't Ask"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"es-MX" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "No preguntar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr-CA" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Ne pas demander"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Double" : {
|
"Double" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -5800,6 +5844,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Skip Insurance Prompt" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Skip Insurance Prompt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"es-MX" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Omitir aviso de seguro"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr-CA" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Ignorer l'invitation d'assurance"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Some games: Dealer hits on 'soft 17' (Ace + 6)." : {
|
"Some games: Dealer hits on 'soft 17' (Ace + 6)." : {
|
||||||
"comment" : "Description of a rule where the dealer must hit on a 'soft 17' (Ace + 6) in some blackjack games.",
|
"comment" : "Description of a rule where the dealer must hit on a 'soft 17' (Ace + 6) in some blackjack games.",
|
||||||
"isCommentAutoGenerated" : true,
|
"isCommentAutoGenerated" : true,
|
||||||
|
|||||||
@ -66,6 +66,7 @@ struct BlackjackSettingsData: PersistableGameData {
|
|||||||
noHoleCard: false,
|
noHoleCard: false,
|
||||||
blackjackPayout: 1.5,
|
blackjackPayout: 1.5,
|
||||||
insuranceAllowed: true,
|
insuranceAllowed: true,
|
||||||
|
neverAskInsurance: false,
|
||||||
sideBetsEnabled: false,
|
sideBetsEnabled: false,
|
||||||
showAnimations: true,
|
showAnimations: true,
|
||||||
dealingSpeed: 1.0,
|
dealingSpeed: 1.0,
|
||||||
@ -90,6 +91,7 @@ struct BlackjackSettingsData: PersistableGameData {
|
|||||||
var noHoleCard: Bool
|
var noHoleCard: Bool
|
||||||
var blackjackPayout: Double
|
var blackjackPayout: Double
|
||||||
var insuranceAllowed: Bool
|
var insuranceAllowed: Bool
|
||||||
|
var neverAskInsurance: Bool
|
||||||
var sideBetsEnabled: Bool
|
var sideBetsEnabled: Bool
|
||||||
var showAnimations: Bool
|
var showAnimations: Bool
|
||||||
var dealingSpeed: Double
|
var dealingSpeed: Double
|
||||||
|
|||||||
@ -121,10 +121,15 @@ enum Design {
|
|||||||
// MARK: - Card Deal Animation
|
// MARK: - Card Deal Animation
|
||||||
|
|
||||||
enum DealAnimation {
|
enum DealAnimation {
|
||||||
/// Horizontal offset for card deal (from upper-right, simulating shoe)
|
/// Horizontal offset for dealer cards (shoe is nearby, less horizontal travel)
|
||||||
static let offsetX: CGFloat = 150
|
static let dealerOffsetX: CGFloat = 120
|
||||||
/// Vertical offset for card deal (from above the table)
|
/// Vertical offset for dealer cards (small since near top)
|
||||||
static let offsetY: CGFloat = -200
|
static let dealerOffsetY: CGFloat = -80
|
||||||
|
|
||||||
|
/// Horizontal offset for player cards (shoe is far away, more horizontal travel)
|
||||||
|
static let playerOffsetX: CGFloat = 180
|
||||||
|
/// Vertical offset for player cards (large since far from top)
|
||||||
|
static let playerOffsetY: CGFloat = -350
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -186,7 +186,8 @@ struct GameTableView: View {
|
|||||||
betAmount: state.currentBet / 2,
|
betAmount: state.currentBet / 2,
|
||||||
balance: state.balance,
|
balance: state.balance,
|
||||||
onTake: { Task { await state.takeInsurance() } },
|
onTake: { Task { await state.takeInsurance() } },
|
||||||
onDecline: { state.declineInsurance() }
|
onDecline: { state.declineInsurance() },
|
||||||
|
onNeverAsk: { state.neverAskInsurance() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|||||||
@ -146,6 +146,15 @@ struct SettingsView: View {
|
|||||||
isOn: $settings.showCardsRemaining,
|
isOn: $settings.showCardsRemaining,
|
||||||
accentColor: accent
|
accentColor: accent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Divider().background(Color.white.opacity(Design.Opacity.hint))
|
||||||
|
|
||||||
|
SettingsToggle(
|
||||||
|
title: String(localized: "Skip Insurance Prompt"),
|
||||||
|
subtitle: String(localized: "Auto-decline when dealer shows Ace"),
|
||||||
|
isOn: $settings.neverAskInsurance,
|
||||||
|
accentColor: accent
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -91,6 +91,8 @@ struct BlackjackTableView: View {
|
|||||||
hand: state.dealerHand,
|
hand: state.dealerHand,
|
||||||
showHoleCard: state.shouldShowDealerHoleCard,
|
showHoleCard: state.shouldShowDealerHoleCard,
|
||||||
showCardCount: showCardCount,
|
showCardCount: showCardCount,
|
||||||
|
showAnimations: state.settings.showAnimations,
|
||||||
|
dealingSpeed: state.settings.dealingSpeed,
|
||||||
cardWidth: cardWidth,
|
cardWidth: cardWidth,
|
||||||
cardSpacing: cardSpacing
|
cardSpacing: cardSpacing
|
||||||
)
|
)
|
||||||
@ -121,6 +123,8 @@ struct BlackjackTableView: View {
|
|||||||
activeHandIndex: state.activeHandIndex,
|
activeHandIndex: state.activeHandIndex,
|
||||||
isPlayerTurn: state.isPlayerTurn,
|
isPlayerTurn: state.isPlayerTurn,
|
||||||
showCardCount: showCardCount,
|
showCardCount: showCardCount,
|
||||||
|
showAnimations: state.settings.showAnimations,
|
||||||
|
dealingSpeed: state.settings.dealingSpeed,
|
||||||
cardWidth: cardWidth,
|
cardWidth: cardWidth,
|
||||||
cardSpacing: cardSpacing,
|
cardSpacing: cardSpacing,
|
||||||
currentHint: state.currentHint,
|
currentHint: state.currentHint,
|
||||||
|
|||||||
@ -12,12 +12,19 @@ struct DealerHandView: View {
|
|||||||
let hand: BlackjackHand
|
let hand: BlackjackHand
|
||||||
let showHoleCard: Bool
|
let showHoleCard: Bool
|
||||||
let showCardCount: Bool
|
let showCardCount: Bool
|
||||||
|
let showAnimations: Bool
|
||||||
|
let dealingSpeed: Double
|
||||||
let cardWidth: CGFloat
|
let cardWidth: CGFloat
|
||||||
let cardSpacing: CGFloat
|
let cardSpacing: CGFloat
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = Design.Size.handLabelFontSize
|
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = Design.Size.handLabelFontSize
|
||||||
@ScaledMetric(relativeTo: .headline) private var badgeHeight: CGFloat = CasinoDesign.Size.valueBadge
|
@ScaledMetric(relativeTo: .headline) private var badgeHeight: CGFloat = CasinoDesign.Size.valueBadge
|
||||||
|
|
||||||
|
/// Scaled animation duration based on dealing speed.
|
||||||
|
private var animationDuration: Double {
|
||||||
|
Design.Animation.springDuration * dealingSpeed
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
||||||
VStack(spacing: Design.Spacing.small) {
|
VStack(spacing: Design.Spacing.small) {
|
||||||
@ -62,12 +69,14 @@ struct DealerHandView: View {
|
|||||||
}
|
}
|
||||||
.zIndex(Double(index))
|
.zIndex(Double(index))
|
||||||
.transition(
|
.transition(
|
||||||
.asymmetric(
|
showAnimations
|
||||||
insertion: .offset(x: Design.DealAnimation.offsetX, y: Design.DealAnimation.offsetY)
|
? .asymmetric(
|
||||||
|
insertion: .offset(x: Design.DealAnimation.dealerOffsetX, y: Design.DealAnimation.dealerOffsetY)
|
||||||
.combined(with: .opacity)
|
.combined(with: .opacity)
|
||||||
.combined(with: .scale(scale: Design.Scale.slightShrink)),
|
.combined(with: .scale(scale: Design.Scale.slightShrink)),
|
||||||
removal: .scale.combined(with: .opacity)
|
removal: .scale.combined(with: .opacity)
|
||||||
)
|
)
|
||||||
|
: .identity
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +87,12 @@ struct DealerHandView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce), value: hand.cards.count)
|
.animation(
|
||||||
|
showAnimations
|
||||||
|
? .spring(duration: animationDuration, bounce: Design.Animation.springBounce)
|
||||||
|
: .none,
|
||||||
|
value: hand.cards.count
|
||||||
|
)
|
||||||
.overlay(alignment: .bottom) {
|
.overlay(alignment: .bottom) {
|
||||||
// Result badge - overlayed so it doesn't add height to the view
|
// Result badge - overlayed so it doesn't add height to the view
|
||||||
if let result = hand.cards.count >= 2 && showHoleCard ? handResultText : nil {
|
if let result = hand.cards.count >= 2 && showHoleCard ? handResultText : nil {
|
||||||
@ -136,6 +150,8 @@ struct DealerHandView: View {
|
|||||||
hand: BlackjackHand(),
|
hand: BlackjackHand(),
|
||||||
showHoleCard: false,
|
showHoleCard: false,
|
||||||
showCardCount: false,
|
showCardCount: false,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20
|
cardSpacing: -20
|
||||||
)
|
)
|
||||||
@ -152,6 +168,8 @@ struct DealerHandView: View {
|
|||||||
]),
|
]),
|
||||||
showHoleCard: false,
|
showHoleCard: false,
|
||||||
showCardCount: false,
|
showCardCount: false,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20
|
cardSpacing: -20
|
||||||
)
|
)
|
||||||
@ -168,6 +186,8 @@ struct DealerHandView: View {
|
|||||||
]),
|
]),
|
||||||
showHoleCard: true,
|
showHoleCard: true,
|
||||||
showCardCount: true,
|
showCardCount: true,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20
|
cardSpacing: -20
|
||||||
)
|
)
|
||||||
|
|||||||
@ -13,6 +13,7 @@ struct InsurancePopupView: View {
|
|||||||
let balance: Int
|
let balance: Int
|
||||||
let onTake: () -> Void
|
let onTake: () -> Void
|
||||||
let onDecline: () -> Void
|
let onDecline: () -> Void
|
||||||
|
let onNeverAsk: () -> Void
|
||||||
|
|
||||||
@State private var showContent = false
|
@State private var showContent = false
|
||||||
|
|
||||||
@ -47,39 +48,50 @@ struct InsurancePopupView: View {
|
|||||||
.padding(.bottom, Design.Spacing.small)
|
.padding(.bottom, Design.Spacing.small)
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
HStack(spacing: Design.Spacing.large) {
|
VStack(spacing: Design.Spacing.medium) {
|
||||||
// Decline button
|
HStack(spacing: Design.Spacing.large) {
|
||||||
Button(action: onDecline) {
|
// Decline button
|
||||||
Text(String(localized: "No Thanks"))
|
Button(action: onDecline) {
|
||||||
.font(.system(size: Design.BaseFontSize.medium, weight: .semibold))
|
Text(String(localized: "No Thanks"))
|
||||||
.foregroundStyle(.white)
|
.font(.system(size: Design.BaseFontSize.medium, weight: .semibold))
|
||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
.foregroundStyle(.white)
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
|
||||||
.background(
|
|
||||||
Capsule()
|
|
||||||
.fill(Color.red.opacity(Design.Opacity.heavy))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept button (only if can afford)
|
|
||||||
if balance >= betAmount {
|
|
||||||
Button(action: onTake) {
|
|
||||||
Text(String(localized: "Yes ($\(betAmount))"))
|
|
||||||
.font(.system(size: Design.BaseFontSize.medium, weight: .bold))
|
|
||||||
.foregroundStyle(.black)
|
|
||||||
.padding(.horizontal, Design.Spacing.xLarge)
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(
|
.fill(Color.red.opacity(Design.Opacity.heavy))
|
||||||
LinearGradient(
|
|
||||||
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
|
|
||||||
startPoint: .top,
|
|
||||||
endPoint: .bottom
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accept button (only if can afford)
|
||||||
|
if balance >= betAmount {
|
||||||
|
Button(action: onTake) {
|
||||||
|
Text(String(localized: "Yes ($\(betAmount))"))
|
||||||
|
.font(.system(size: Design.BaseFontSize.medium, weight: .bold))
|
||||||
|
.foregroundStyle(.black)
|
||||||
|
.padding(.horizontal, Design.Spacing.xLarge)
|
||||||
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
|
.background(
|
||||||
|
Capsule()
|
||||||
|
.fill(
|
||||||
|
LinearGradient(
|
||||||
|
colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
|
||||||
|
startPoint: .top,
|
||||||
|
endPoint: .bottom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't Ask Again button
|
||||||
|
Button(action: onNeverAsk) {
|
||||||
|
Text(String(localized: "Don't Ask"))
|
||||||
|
.font(.system(size: Design.BaseFontSize.small, weight: .medium))
|
||||||
|
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||||
|
.padding(.horizontal, Design.Spacing.large)
|
||||||
|
.padding(.vertical, Design.Spacing.small)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +125,8 @@ struct InsurancePopupView: View {
|
|||||||
betAmount: 500,
|
betAmount: 500,
|
||||||
balance: 4500,
|
balance: 4500,
|
||||||
onTake: {},
|
onTake: {},
|
||||||
onDecline: {}
|
onDecline: {},
|
||||||
|
onNeverAsk: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +135,8 @@ struct InsurancePopupView: View {
|
|||||||
betAmount: 500,
|
betAmount: 500,
|
||||||
balance: 200,
|
balance: 200,
|
||||||
onTake: {},
|
onTake: {},
|
||||||
onDecline: {}
|
onDecline: {},
|
||||||
|
onNeverAsk: {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,8 @@ struct PlayerHandsView: View {
|
|||||||
let activeHandIndex: Int
|
let activeHandIndex: Int
|
||||||
let isPlayerTurn: Bool
|
let isPlayerTurn: Bool
|
||||||
let showCardCount: Bool
|
let showCardCount: Bool
|
||||||
|
let showAnimations: Bool
|
||||||
|
let dealingSpeed: Double
|
||||||
let cardWidth: CGFloat
|
let cardWidth: CGFloat
|
||||||
let cardSpacing: CGFloat
|
let cardSpacing: CGFloat
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ struct PlayerHandsView: View {
|
|||||||
hand: hand,
|
hand: hand,
|
||||||
isActive: isActiveHand,
|
isActive: isActiveHand,
|
||||||
showCardCount: showCardCount,
|
showCardCount: showCardCount,
|
||||||
|
showAnimations: showAnimations,
|
||||||
|
dealingSpeed: dealingSpeed,
|
||||||
// Hand numbers: rightmost (index 0) is Hand 1, played first
|
// Hand numbers: rightmost (index 0) is Hand 1, played first
|
||||||
handNumber: hands.count > 1 ? index + 1 : nil,
|
handNumber: hands.count > 1 ? index + 1 : nil,
|
||||||
cardWidth: cardWidth,
|
cardWidth: cardWidth,
|
||||||
@ -95,6 +99,8 @@ struct PlayerHandView: View {
|
|||||||
let hand: BlackjackHand
|
let hand: BlackjackHand
|
||||||
let isActive: Bool
|
let isActive: Bool
|
||||||
let showCardCount: Bool
|
let showCardCount: Bool
|
||||||
|
let showAnimations: Bool
|
||||||
|
let dealingSpeed: Double
|
||||||
let handNumber: Int?
|
let handNumber: Int?
|
||||||
let cardWidth: CGFloat
|
let cardWidth: CGFloat
|
||||||
let cardSpacing: CGFloat
|
let cardSpacing: CGFloat
|
||||||
@ -105,6 +111,11 @@ struct PlayerHandView: View {
|
|||||||
/// Whether the hint toast should be visible.
|
/// Whether the hint toast should be visible.
|
||||||
let showHintToast: Bool
|
let showHintToast: Bool
|
||||||
|
|
||||||
|
/// Scaled animation duration based on dealing speed.
|
||||||
|
private var animationDuration: Double {
|
||||||
|
Design.Animation.springDuration * dealingSpeed
|
||||||
|
}
|
||||||
|
|
||||||
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = Design.Size.handLabelFontSize
|
@ScaledMetric(relativeTo: .headline) private var labelFontSize: CGFloat = Design.Size.handLabelFontSize
|
||||||
@ScaledMetric(relativeTo: .caption) private var handNumberSize: CGFloat = Design.Size.handNumberFontSize
|
@ScaledMetric(relativeTo: .caption) private var handNumberSize: CGFloat = Design.Size.handNumberFontSize
|
||||||
@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = Design.Size.handIconSize
|
@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = Design.Size.handIconSize
|
||||||
@ -132,17 +143,24 @@ struct PlayerHandView: View {
|
|||||||
}
|
}
|
||||||
.zIndex(Double(index))
|
.zIndex(Double(index))
|
||||||
.transition(
|
.transition(
|
||||||
.asymmetric(
|
showAnimations
|
||||||
insertion: .offset(x: Design.DealAnimation.offsetX, y: Design.DealAnimation.offsetY)
|
? .asymmetric(
|
||||||
|
insertion: .offset(x: Design.DealAnimation.playerOffsetX, y: Design.DealAnimation.playerOffsetY)
|
||||||
.combined(with: .opacity)
|
.combined(with: .opacity)
|
||||||
.combined(with: .scale(scale: Design.Scale.slightShrink)),
|
.combined(with: .scale(scale: Design.Scale.slightShrink)),
|
||||||
removal: .scale.combined(with: .opacity)
|
removal: .scale.combined(with: .opacity)
|
||||||
)
|
)
|
||||||
|
: .identity
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce), value: hand.cards.count)
|
.animation(
|
||||||
|
showAnimations
|
||||||
|
? .spring(duration: animationDuration, bounce: Design.Animation.springBounce)
|
||||||
|
: .none,
|
||||||
|
value: hand.cards.count
|
||||||
|
)
|
||||||
.padding(.horizontal, Design.Spacing.medium)
|
.padding(.horizontal, Design.Spacing.medium)
|
||||||
.padding(.vertical, Design.Spacing.medium)
|
.padding(.vertical, Design.Spacing.medium)
|
||||||
.background(
|
.background(
|
||||||
@ -246,6 +264,8 @@ struct PlayerHandView: View {
|
|||||||
activeHandIndex: 0,
|
activeHandIndex: 0,
|
||||||
isPlayerTurn: true,
|
isPlayerTurn: true,
|
||||||
showCardCount: false,
|
showCardCount: false,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20,
|
cardSpacing: -20,
|
||||||
currentHint: nil,
|
currentHint: nil,
|
||||||
@ -265,6 +285,8 @@ struct PlayerHandView: View {
|
|||||||
activeHandIndex: 0,
|
activeHandIndex: 0,
|
||||||
isPlayerTurn: true,
|
isPlayerTurn: true,
|
||||||
showCardCount: false,
|
showCardCount: false,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20,
|
cardSpacing: -20,
|
||||||
currentHint: "Hit",
|
currentHint: "Hit",
|
||||||
@ -298,6 +320,8 @@ struct PlayerHandView: View {
|
|||||||
activeHandIndex: 1,
|
activeHandIndex: 1,
|
||||||
isPlayerTurn: true,
|
isPlayerTurn: true,
|
||||||
showCardCount: true,
|
showCardCount: true,
|
||||||
|
showAnimations: true,
|
||||||
|
dealingSpeed: 1.0,
|
||||||
cardWidth: 60,
|
cardWidth: 60,
|
||||||
cardSpacing: -20,
|
cardSpacing: -20,
|
||||||
currentHint: "Stand",
|
currentHint: "Stand",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user