153 lines
4.8 KiB
Swift
153 lines
4.8 KiB
Swift
//
|
|
// SideBetZoneView.swift
|
|
// Blackjack
|
|
//
|
|
// Side bet zone for Perfect Pairs and 21+3.
|
|
//
|
|
|
|
import SwiftUI
|
|
import CasinoKit
|
|
|
|
/// A tappable zone for placing side bets.
|
|
struct SideBetZoneView: View {
|
|
let betType: SideBetType
|
|
let betAmount: Int
|
|
let isEnabled: Bool
|
|
let isAtMax: Bool
|
|
let onTap: () -> Void
|
|
|
|
@ScaledMetric(relativeTo: .callout) private var labelFontSize: CGFloat = Design.Size.sideBetLabelFontSize
|
|
@ScaledMetric(relativeTo: .caption) private var payoutFontSize: CGFloat = Design.Size.sideBetPayoutFontSize
|
|
|
|
private var backgroundColor: Color {
|
|
switch betType {
|
|
case .perfectPairs:
|
|
return Color.SideBet.perfectPairs
|
|
case .twentyOnePlusThree:
|
|
return Color.SideBet.twentyOnePlusThree
|
|
}
|
|
}
|
|
|
|
private var payoutText: String {
|
|
switch betType {
|
|
case .perfectPairs:
|
|
return "25:1" // Best payout shown
|
|
case .twentyOnePlusThree:
|
|
return "100:1" // Best payout shown
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
Button {
|
|
if isEnabled { onTap() }
|
|
} label: {
|
|
ZStack {
|
|
// Background
|
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
|
.fill(backgroundColor)
|
|
.overlay(
|
|
RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
|
|
.strokeBorder(
|
|
Color.white.opacity(Design.Opacity.hint),
|
|
lineWidth: Design.LineWidth.medium
|
|
)
|
|
)
|
|
|
|
// Content
|
|
VStack(spacing: Design.Spacing.xxSmall) {
|
|
Text(betType.shortName)
|
|
.font(.system(size: labelFontSize, weight: .black, design: .rounded))
|
|
.foregroundStyle(.yellow)
|
|
|
|
Text(payoutText)
|
|
.font(.system(size: payoutFontSize, weight: .medium, design: .rounded))
|
|
.foregroundStyle(.white.opacity(Design.Opacity.strong))
|
|
}
|
|
|
|
// Chip indicator - top right
|
|
if betAmount > 0 {
|
|
VStack {
|
|
HStack {
|
|
Spacer()
|
|
ChipBadgeView(amount: betAmount, isMax: isAtMax)
|
|
.padding(Design.Spacing.xSmall)
|
|
}
|
|
Spacer()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.buttonStyle(.plain)
|
|
.opacity(isEnabled ? 1.0 : Design.Opacity.medium)
|
|
.accessibilityLabel("\(betType.displayName) bet, pays up to \(payoutText)")
|
|
.accessibilityHint(betAmount > 0 ? "Current bet $\(betAmount)" : "Double tap to place bet")
|
|
}
|
|
}
|
|
|
|
/// Small chip badge for side bet indicators.
|
|
struct ChipBadgeView: View {
|
|
let amount: Int
|
|
let isMax: Bool
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
Circle()
|
|
.fill(isMax ? Color.gray : Color.yellow)
|
|
.frame(width: CasinoDesign.Size.chipBadge, height: CasinoDesign.Size.chipBadge)
|
|
|
|
Circle()
|
|
.strokeBorder(Color.white.opacity(Design.Opacity.almostFull), lineWidth: Design.LineWidth.thin)
|
|
.frame(width: CasinoDesign.Size.chipBadgeInner, height: CasinoDesign.Size.chipBadgeInner)
|
|
|
|
if isMax {
|
|
Text(String(localized: "MAX"))
|
|
.font(.system(size: Design.BaseFontSize.xxSmall, weight: .black))
|
|
.foregroundStyle(.white)
|
|
} else {
|
|
Text(formatCompact(amount))
|
|
.font(.system(size: Design.BaseFontSize.small, weight: .bold, design: .rounded))
|
|
.foregroundStyle(.black)
|
|
}
|
|
}
|
|
.shadow(color: .black.opacity(Design.Opacity.light), radius: Design.Shadow.radiusSmall, y: Design.Shadow.offsetSmall)
|
|
}
|
|
|
|
private func formatCompact(_ value: Int) -> String {
|
|
if value >= 1000 {
|
|
return "\(value / 1000)K"
|
|
}
|
|
return "\(value)"
|
|
}
|
|
}
|
|
|
|
// MARK: - Previews
|
|
|
|
#Preview("Perfect Pairs") {
|
|
ZStack {
|
|
Color.Table.felt.ignoresSafeArea()
|
|
SideBetZoneView(
|
|
betType: .perfectPairs,
|
|
betAmount: 0,
|
|
isEnabled: true,
|
|
isAtMax: false,
|
|
onTap: {}
|
|
)
|
|
.frame(width: 80, height: 70)
|
|
}
|
|
}
|
|
|
|
#Preview("21+3 with Bet") {
|
|
ZStack {
|
|
Color.Table.felt.ignoresSafeArea()
|
|
SideBetZoneView(
|
|
betType: .twentyOnePlusThree,
|
|
betAmount: 25,
|
|
isEnabled: true,
|
|
isAtMax: false,
|
|
onTap: {}
|
|
)
|
|
.frame(width: 80, height: 70)
|
|
}
|
|
}
|
|
|