Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2025-12-28 18:01:37 -06:00
parent dfe3bc4bba
commit 172e224a42

View File

@ -21,8 +21,10 @@ struct ActionButtonsView: View {
switch state.currentPhase {
case .betting:
bettingButtons
.transition(.opacity.combined(with: .scale(scale: 0.9)))
case .playerTurn:
playerTurnButtons
.transition(.opacity.combined(with: .scale(scale: 0.9)))
case .roundComplete:
// Empty - handled by result banner
EmptyView()
@ -31,6 +33,7 @@ struct ActionButtonsView: View {
EmptyView()
}
}
.animation(.spring(duration: Design.Animation.springDuration), value: state.currentPhase)
}
.frame(height: containerHeight)
.padding(.horizontal, Design.Spacing.large)
@ -51,54 +54,86 @@ struct ActionButtonsView: View {
// MARK: - Player Turn Buttons
/// Available player actions based on current game state.
private var availableActions: [PlayerAction] {
PlayerAction.allCases.filter { action in
switch action {
case .hit: state.canHit
case .stand: state.canStand
case .double: state.canDouble
case .split: state.canSplit
case .surrender: state.canSurrender
}
}
}
/// Tracks available actions for animation purposes.
@State private var animatedActions: [PlayerAction] = []
@ViewBuilder
private var playerTurnButtons: some View {
// All player actions in a single row
HStack(spacing: Design.Spacing.medium) {
if state.canHit {
ForEach(animatedActions) { action in
ActionButton(
String(localized: "Hit"),
style: .custom(Color.Button.hit)
action.title,
style: .custom(action.color)
) {
Task { await state.hit() }
Task { await performAction(action) }
}
.transition(.scale.combined(with: .opacity))
}
}
.onAppear {
animatedActions = availableActions
}
.onChange(of: availableActions) { _, newActions in
withAnimation(.spring(duration: Design.Animation.springDuration, bounce: 0.15)) {
animatedActions = newActions
}
}
}
if state.canStand {
ActionButton(
String(localized: "Stand"),
style: .custom(Color.Button.stand)
) {
Task { await state.stand() }
/// Performs the given player action.
private func performAction(_ action: PlayerAction) async {
switch action {
case .hit: await state.hit()
case .stand: await state.stand()
case .double: await state.doubleDown()
case .split: await state.split()
case .surrender: await state.surrender()
}
}
}
// MARK: - Player Action
/// Represents a player action button during their turn.
private enum PlayerAction: String, CaseIterable, Identifiable {
case hit
case stand
case double
case split
case surrender
var id: String { rawValue }
var title: String {
switch self {
case .hit: String(localized: "Hit")
case .stand: String(localized: "Stand")
case .double: String(localized: "Double")
case .split: String(localized: "Split")
case .surrender: String(localized: "Surrender")
}
}
if state.canDouble {
ActionButton(
String(localized: "Double"),
style: .custom(Color.Button.doubleDown)
) {
Task { await state.doubleDown() }
}
}
if state.canSplit {
ActionButton(
String(localized: "Split"),
style: .custom(Color.Button.split)
) {
Task { await state.split() }
}
}
if state.canSurrender {
ActionButton(
String(localized: "Surrender"),
style: .custom(Color.Button.surrender)
) {
Task { await state.surrender() }
}
}
var color: Color {
switch self {
case .hit: Color.Button.hit
case .stand: Color.Button.stand
case .double: Color.Button.doubleDown
case .split: Color.Button.split
case .surrender: Color.Button.surrender
}
}
}