// // SettingsView.swift // Blackjack // // Game settings and rule configuration. // import SwiftUI import CasinoKit struct SettingsView: View { @Bindable var settings: GameSettings let gameState: GameState? @Environment(\.dismiss) private var dismiss var body: some View { SheetContainerView( title: String(localized: "Settings"), content: { // Game Style SheetSection(title: String(localized: "GAME STYLE"), icon: "suit.club.fill") { GameStylePicker(selection: $settings.gameStyle) } // Deck Settings SheetSection(title: String(localized: "DECK SETTINGS"), icon: "rectangle.portrait.on.rectangle.portrait") { DeckCountPicker(selection: $settings.deckCount) } .onChange(of: settings.deckCount) { _, _ in // Reshuffle with new deck count gameState?.applyDeckCountChange() } // Table Limits SheetSection(title: String(localized: "TABLE LIMITS"), icon: "banknote") { TableLimitsPicker(selection: $settings.tableLimits) } // Rule Options (for custom style) if settings.gameStyle == .custom { SheetSection(title: String(localized: "RULES"), icon: "list.bullet.clipboard") { VStack(spacing: Design.Spacing.small) { SettingsToggle( title: String(localized: "Dealer Hits Soft 17"), subtitle: String(localized: "H17 rule, increases house edge"), isOn: $settings.dealerHitsSoft17 ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Double After Split"), subtitle: String(localized: "Allow doubling on split hands"), isOn: $settings.doubleAfterSplit ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Re-split Aces"), subtitle: String(localized: "Allow splitting aces again"), isOn: $settings.resplitAces ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Late Surrender"), subtitle: String(localized: "Surrender after dealer checks for blackjack"), isOn: $settings.lateSurrender ) } } } // Display SheetSection(title: String(localized: "DISPLAY"), icon: "eye") { VStack(spacing: Design.Spacing.small) { SettingsToggle( title: String(localized: "Show Animations"), subtitle: String(localized: "Card dealing animations"), isOn: $settings.showAnimations ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Show Hints"), subtitle: String(localized: "Basic strategy suggestions"), isOn: $settings.showHints ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Card Count"), subtitle: String(localized: "Show Hi-Lo running count & card values"), isOn: $settings.showCardCount ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Cards Remaining"), subtitle: String(localized: "Show cards left in shoe"), isOn: $settings.showCardsRemaining ) Divider().background(Color.white.opacity(Design.Opacity.hint)) SpeedPicker(speed: $settings.dealingSpeed) } } // Sound & Haptics SheetSection(title: String(localized: "SOUND & HAPTICS"), icon: "speaker.wave.2") { VStack(spacing: Design.Spacing.small) { SettingsToggle( title: String(localized: "Sound Effects"), subtitle: String(localized: "Chips, cards, and results"), isOn: $settings.soundEnabled ) .onChange(of: settings.soundEnabled) { _, newValue in SoundManager.shared.soundEnabled = newValue } Divider().background(Color.white.opacity(Design.Opacity.hint)) SettingsToggle( title: String(localized: "Haptic Feedback"), subtitle: String(localized: "Vibration on actions"), isOn: $settings.hapticsEnabled ) .onChange(of: settings.hapticsEnabled) { _, newValue in SoundManager.shared.hapticsEnabled = newValue } Divider().background(Color.white.opacity(Design.Opacity.hint)) VolumePicker(volume: $settings.soundVolume) .onChange(of: settings.soundVolume) { _, newValue in SoundManager.shared.volume = newValue } } } // Starting Balance SheetSection(title: String(localized: "NEW GAME"), icon: "dollarsign.circle") { BalancePicker(balance: $settings.startingBalance) } // Version info if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { Text(String(localized: "Version \(version) (\(build))")) .font(.system(size: Design.BaseFontSize.small)) .foregroundStyle(.white.opacity(Design.Opacity.light)) .frame(maxWidth: .infinity) .padding(.top, Design.Spacing.large) } }, onCancel: nil, onDone: { settings.save() dismiss() }, doneButtonText: String(localized: "Done") ) } } // MARK: - Game Style Picker struct GameStylePicker: View { @Binding var selection: BlackjackStyle var body: some View { VStack(spacing: Design.Spacing.small) { ForEach(BlackjackStyle.allCases) { style in SelectableRow( title: style.displayName, subtitle: style.description, isSelected: selection == style, accentColor: Color.Settings.accent, action: { selection = style } ) } } } } // MARK: - Deck Count Picker struct DeckCountPicker: View { @Binding var selection: DeckCount var body: some View { VStack(spacing: Design.Spacing.medium) { ForEach(DeckCount.allCases) { count in SelectableRow( title: count.displayName, subtitle: count.description, isSelected: selection == count, accentColor: Color.Settings.accent, action: { selection = count } ) } } } } // MARK: - Table Limits Picker struct TableLimitsPicker: View { @Binding var selection: TableLimits var body: some View { VStack(spacing: Design.Spacing.small) { ForEach(TableLimits.allCases) { limit in SelectableRow( title: limit.displayName, subtitle: limit.detailedDescription, isSelected: selection == limit, accentColor: Color.Settings.accent, badge: { BadgePill(text: limit.description, isSelected: selection == limit, accentColor: Color.Settings.accent) }, action: { selection = limit } ) } } } } #Preview { SettingsView(settings: GameSettings(), gameState: nil) }