Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
09770ec625
commit
7234cd718a
@ -2832,6 +2832,52 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reset Game" : {
|
||||
"comment" : "A button label that resets the game balance and reshuffles the deck.",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Reset Game"
|
||||
}
|
||||
},
|
||||
"es-MX" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Reiniciar juego"
|
||||
}
|
||||
},
|
||||
"fr-CA" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Réinitialiser la partie"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Restore starting balance and reshuffle" : {
|
||||
"comment" : "Description for the reset game button explaining what it does.",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Restore starting balance and reshuffle"
|
||||
}
|
||||
},
|
||||
"es-MX" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Restaurar saldo inicial y barajar"
|
||||
}
|
||||
},
|
||||
"fr-CA" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Restaurer le solde initial et mélanger"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reset to Defaults" : {
|
||||
"comment" : "A button label that resets game settings to their default values.",
|
||||
"localizations" : {
|
||||
|
||||
@ -135,7 +135,7 @@ struct GameTableView: View {
|
||||
balance: state.balance,
|
||||
secondaryInfo: settings.showCardsRemaining ? "\(state.engine.shoe.cardsRemaining)" : nil,
|
||||
secondaryIcon: settings.showCardsRemaining ? "rectangle.portrait.on.rectangle.portrait.fill" : nil,
|
||||
onReset: { state.resetGame() },
|
||||
showReset: false,
|
||||
onSettings: { showSettings = true },
|
||||
onHelp: { showRules = true },
|
||||
onStats: { showStats = true }
|
||||
@ -256,7 +256,7 @@ struct GameTableView: View {
|
||||
balance: state.balance,
|
||||
secondaryInfo: settings.showCardsRemaining ? "\(state.engine.shoe.cardsRemaining)" : nil,
|
||||
secondaryIcon: settings.showCardsRemaining ? "rectangle.portrait.on.rectangle.portrait.fill" : nil,
|
||||
onReset: { state.resetGame() },
|
||||
showReset: false,
|
||||
onSettings: { showSettings = true },
|
||||
onHelp: { showRules = true },
|
||||
onStats: { showStats = true }
|
||||
|
||||
@ -150,7 +150,7 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
.tint(accent)
|
||||
.padding(.vertical, Design.Spacing.xSmall)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
|
||||
if gameState.iCloudEnabled {
|
||||
Divider()
|
||||
@ -173,6 +173,7 @@ struct SettingsView: View {
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
@ -181,11 +182,13 @@ struct SettingsView: View {
|
||||
gameState.syncWithCloud()
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "arrow.triangle.2.circlepath")
|
||||
Text(String(localized: "Sync Now"))
|
||||
Spacer()
|
||||
Image(systemName: "arrow.triangle.2.circlepath")
|
||||
}
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
.foregroundStyle(accent)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -203,7 +206,7 @@ struct SettingsView: View {
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
}
|
||||
.padding(.vertical, Design.Spacing.xSmall)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,15 +240,43 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
|
||||
// Reset Game - resets balance, keeps stats
|
||||
Button {
|
||||
gameState.resetGame()
|
||||
dismiss()
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||
Text(String(localized: "Reset Game"))
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
.foregroundStyle(.white)
|
||||
Text(String(localized: "Restore starting balance and reshuffle"))
|
||||
.font(.system(size: Design.BaseFontSize.small))
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "arrow.counterclockwise")
|
||||
.font(.system(size: Design.BaseFontSize.large))
|
||||
.foregroundStyle(Color.Sheet.accent)
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
|
||||
// Clear All Data - nuclear option
|
||||
Button(role: .destructive) {
|
||||
showClearDataAlert = true
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "trash")
|
||||
Text(String(localized: "Clear All Data"))
|
||||
Spacer()
|
||||
Image(systemName: "trash")
|
||||
}
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
.foregroundStyle(.red)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +294,7 @@ struct SettingsView: View {
|
||||
.font(.system(size: Design.BaseFontSize.body))
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5434,6 +5434,52 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Reset Game": {
|
||||
"comment": "Button to reset game balance and reshuffle cards.",
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Reset Game"
|
||||
}
|
||||
},
|
||||
"es-MX": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Reiniciar Juego"
|
||||
}
|
||||
},
|
||||
"fr-CA": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Réinitialiser le Jeu"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Restore starting balance and reshuffle": {
|
||||
"comment": "Subtitle for Reset Game button explaining what it does.",
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Restore starting balance and reshuffle"
|
||||
}
|
||||
},
|
||||
"es-MX": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Restaurar saldo inicial y barajar"
|
||||
}
|
||||
},
|
||||
"fr-CA": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Restaurer le solde initial et remélanger"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Running Count: Sum of all card values seen.": {
|
||||
"localizations": {
|
||||
"en": {
|
||||
|
||||
@ -97,7 +97,7 @@ struct GameTableView: View {
|
||||
balance: state.balance,
|
||||
secondaryInfo: settings.showCardsRemaining ? "\(state.engine.cardsRemaining)" : nil,
|
||||
secondaryIcon: settings.showCardsRemaining ? "rectangle.portrait.on.rectangle.portrait.fill" : nil,
|
||||
onReset: { state.resetGame() },
|
||||
showReset: false,
|
||||
onSettings: { showSettings = true },
|
||||
onHelp: { showRules = true },
|
||||
onStats: { showStats = true }
|
||||
@ -105,16 +105,6 @@ struct GameTableView: View {
|
||||
.frame(maxWidth: maxContentWidth)
|
||||
.debugBorder(showDebugBorders, color: .cyan, label: "TopBar")
|
||||
|
||||
// Card count display (when enabled)
|
||||
if settings.showCardCount {
|
||||
CardCountView(
|
||||
runningCount: state.engine.runningCount,
|
||||
trueCount: state.engine.trueCount
|
||||
)
|
||||
.frame(maxWidth: maxContentWidth)
|
||||
.debugBorder(showDebugBorders, color: .mint, label: "CardCount")
|
||||
}
|
||||
|
||||
// Reshuffle notification
|
||||
if state.showReshuffleNotification {
|
||||
ReshuffleNotificationView(showCardCount: settings.showCardCount)
|
||||
|
||||
@ -204,7 +204,7 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
.tint(accent)
|
||||
.padding(.vertical, Design.Spacing.xSmall)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
|
||||
if state.persistence.iCloudEnabled {
|
||||
Divider()
|
||||
@ -227,6 +227,7 @@ struct SettingsView: View {
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
@ -235,11 +236,13 @@ struct SettingsView: View {
|
||||
state.persistence.sync()
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "arrow.triangle.2.circlepath")
|
||||
Text(String(localized: "Sync Now"))
|
||||
Spacer()
|
||||
Image(systemName: "arrow.triangle.2.circlepath")
|
||||
}
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
.foregroundStyle(accent)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -257,7 +260,7 @@ struct SettingsView: View {
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
}
|
||||
.padding(.vertical, Design.Spacing.xSmall)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,15 +296,44 @@ struct SettingsView: View {
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
|
||||
// Reset Game - resets balance, keeps stats
|
||||
Button {
|
||||
state.resetGame()
|
||||
dismiss()
|
||||
} label: {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: Design.Spacing.xxSmall) {
|
||||
Text(String(localized: "Reset Game"))
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
.foregroundStyle(.white)
|
||||
Text(String(localized: "Restore starting balance and reshuffle"))
|
||||
.font(.system(size: Design.BaseFontSize.small))
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "arrow.counterclockwise")
|
||||
.font(.system(size: Design.BaseFontSize.large))
|
||||
.foregroundStyle(Color.Sheet.accent)
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
|
||||
Divider()
|
||||
.background(Color.white.opacity(Design.Opacity.subtle))
|
||||
|
||||
// Clear All Data - nuclear option
|
||||
Button(role: .destructive) {
|
||||
showClearDataAlert = true
|
||||
} label: {
|
||||
HStack {
|
||||
Image(systemName: "trash")
|
||||
Text(String(localized: "Clear All Data"))
|
||||
}
|
||||
.font(.system(size: Design.BaseFontSize.body, weight: .medium))
|
||||
Spacer()
|
||||
Image(systemName: "trash")
|
||||
.font(.system(size: Design.BaseFontSize.large))
|
||||
}
|
||||
.foregroundStyle(.red)
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -320,6 +352,7 @@ struct SettingsView: View {
|
||||
.font(.system(size: Design.BaseFontSize.body))
|
||||
.foregroundStyle(.white.opacity(Design.Opacity.medium))
|
||||
}
|
||||
.frame(minHeight: CasinoDesign.Size.actionRowMinHeight)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ struct BlackjackTableView: View {
|
||||
/// Card width based on full screen height (stable - doesn't change with content)
|
||||
private var cardWidth: CGFloat {
|
||||
let maxDimension = screenHeight
|
||||
let percentage: CGFloat = 0.13 // ~10% of screen
|
||||
let percentage: CGFloat = 0.15 // ~10% of screen
|
||||
return maxDimension * percentage
|
||||
}
|
||||
|
||||
@ -93,9 +93,32 @@ struct BlackjackTableView: View {
|
||||
)
|
||||
.debugBorder(showDebugBorders, color: .red, label: "Dealer")
|
||||
|
||||
// Flexible space between dealer and player - scales with screen size
|
||||
// Space between dealer and player - contains card count if enabled
|
||||
if showCardCount {
|
||||
// Card count view fills the space between hands
|
||||
VStack {
|
||||
// Top spacer for larger screens
|
||||
if screenHeight > 700 {
|
||||
Spacer(minLength: Design.Spacing.small)
|
||||
}
|
||||
|
||||
CardCountView(
|
||||
runningCount: state.engine.runningCount,
|
||||
trueCount: state.engine.trueCount
|
||||
)
|
||||
|
||||
// Bottom spacer for larger screens
|
||||
if screenHeight > 700 {
|
||||
Spacer(minLength: Design.Spacing.small)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: dealerPlayerSpacing)
|
||||
.debugBorder(showDebugBorders, color: .mint, label: "CardCount")
|
||||
} else {
|
||||
// No card count - just use flexible spacer
|
||||
Spacer(minLength: dealerPlayerSpacing)
|
||||
.debugBorder(showDebugBorders, color: .yellow, label: "Spacer \(Int(dealerPlayerSpacing))")
|
||||
}
|
||||
|
||||
// Player hands area - only show when there are cards dealt
|
||||
if state.playerHands.first?.cards.isEmpty == false {
|
||||
|
||||
@ -147,6 +147,9 @@ public enum CasinoDesign {
|
||||
/// Checkmark size.
|
||||
public static let checkmark: CGFloat = 22
|
||||
|
||||
/// Minimum height for tappable action rows (Apple HIG: 44pt minimum touch target).
|
||||
public static let actionRowMinHeight: CGFloat = 44
|
||||
|
||||
/// Common button dimensions.
|
||||
public static let actionButtonHeight: CGFloat = 50
|
||||
public static var actionButtonMinWidth: CGFloat {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user