CasinoGames/Baccarat/Views/Chips/ChipOnTable.swift

118 lines
3.6 KiB
Swift

//
// ChipOnTable.swift
// Baccarat
//
// A simplified chip display for showing bets on the table.
//
import SwiftUI
/// A simplified chip for displaying bets on the table.
struct ChipOnTable: View {
let amount: Int
var showMax: Bool = false
// MARK: - Layout Constants
// Fixed sizes: chip face has strict space constraints
private let chipSize = Design.Size.chipSmall
private let innerRingSize: CGFloat = 26
private let gradientEndRadius: CGFloat = 20
private let maxBadgeFontSize = Design.BaseFontSize.xxSmall
private let maxBadgeOffsetX: CGFloat = 6
private let maxBadgeOffsetY: CGFloat = -4
// MARK: - Computed Properties
private var chipColor: Color {
switch amount {
case 0..<50: return .blue
case 50..<100: return .orange
case 100..<500: return .black
case 500..<1000: return .purple
default: return Color.Chip.gold
}
}
private var displayText: String {
amount >= 1000 ? "\(amount / 1000)K" : "\(amount)"
}
private var textFontSize: CGFloat {
amount >= 1000 ? Design.BaseFontSize.small : 11
}
// MARK: - Body
var body: some View {
ZStack {
Circle()
.fill(
RadialGradient(
colors: [chipColor.opacity(0.9), chipColor],
center: .topLeading,
startRadius: 0,
endRadius: gradientEndRadius
)
)
.frame(width: chipSize, height: chipSize)
Circle()
.strokeBorder(Color.white.opacity(Design.Opacity.heavy), lineWidth: Design.LineWidth.medium)
.frame(width: chipSize, height: chipSize)
Circle()
.strokeBorder(Color.white.opacity(Design.Opacity.light), lineWidth: Design.LineWidth.thin)
.frame(width: innerRingSize, height: innerRingSize)
Text(displayText)
.font(.system(size: textFontSize, weight: .bold))
.foregroundStyle(.white)
}
.shadow(color: .black.opacity(Design.Opacity.light), radius: Design.Shadow.radiusSmall, x: 1, y: 2)
.overlay(alignment: .topTrailing) {
if showMax {
Text("MAX")
.font(.system(size: maxBadgeFontSize, weight: .black))
.foregroundStyle(.white)
.padding(.horizontal, Design.Spacing.xSmall)
.padding(.vertical, Design.Spacing.xxSmall)
.background(
Capsule()
.fill(Color.red)
)
.offset(x: maxBadgeOffsetX, y: maxBadgeOffsetY)
.accessibilityHidden(true) // Included in parent label
}
}
.accessibilityLabel(accessibilityDescription)
}
// MARK: - Accessibility
private var accessibilityDescription: String {
let format = String(localized: "betAmountFormat")
let base = String(format: format, amount.formatted())
if showMax {
return base + ", " + String(localized: "maximum bet")
}
return base
}
}
#Preview {
ZStack {
Color.Table.preview
.ignoresSafeArea()
HStack(spacing: Design.Spacing.xLarge) {
ChipOnTable(amount: 25)
ChipOnTable(amount: 100)
ChipOnTable(amount: 500)
ChipOnTable(amount: 1000)
ChipOnTable(amount: 5000, showMax: true)
}
}
}