CasinoGames/CasinoKit/Sources/CasinoKit/Views/BettingHintView.swift

172 lines
5.3 KiB
Swift

//
// BettingHintView.swift
// CasinoKit
//
// A shared betting hint view for displaying recommendations across casino games.
//
import SwiftUI
/// Style of the betting hint (affects color and icon).
public enum BettingHintStyle {
/// Positive/favorable hint (green)
case positive
/// Negative/warning hint (red)
case negative
/// Neutral/informational hint (yellow)
case neutral
/// Streak-based hint (orange/flame)
case streak
/// Choppy/alternating pattern (blue)
case pattern
/// Custom color
case custom(Color, String)
public var color: Color {
switch self {
case .positive: return .green
case .negative: return .red
case .neutral: return .yellow
case .streak: return .orange
case .pattern: return .blue
case .custom(let color, _): return color
}
}
public var icon: String {
switch self {
case .positive: return "arrow.up.circle.fill"
case .negative: return "arrow.down.circle.fill"
case .neutral: return "lightbulb.fill"
case .streak: return "flame.fill"
case .pattern: return "arrow.left.arrow.right"
case .custom(_, let icon): return icon
}
}
}
/// A shared betting hint view for casino games.
/// Shows betting recommendations with consistent styling.
public struct BettingHintView: View {
/// The main hint text.
public let hint: String
/// Optional secondary info (e.g., trend percentage).
public let secondaryInfo: String?
/// The style of the hint (determines color and icon).
public let style: BettingHintStyle
// MARK: - Scaled Metrics
@ScaledMetric(relativeTo: .body) private var iconSize: CGFloat = CasinoDesign.HintSize.iconSize
@ScaledMetric(relativeTo: .body) private var fontSize: CGFloat = CasinoDesign.HintSize.fontSize
@ScaledMetric(relativeTo: .body) private var paddingH: CGFloat = CasinoDesign.HintSize.paddingH
@ScaledMetric(relativeTo: .body) private var paddingV: CGFloat = CasinoDesign.HintSize.paddingV
/// Creates a betting hint view.
/// - Parameters:
/// - hint: The main hint text.
/// - secondaryInfo: Optional secondary info text.
/// - style: The visual style of the hint.
public init(hint: String, secondaryInfo: String? = nil, style: BettingHintStyle = .neutral) {
self.hint = hint
self.secondaryInfo = secondaryInfo
self.style = style
}
public var body: some View {
HStack(spacing: CasinoDesign.Spacing.small) {
Image(systemName: style.icon)
.font(.system(size: iconSize))
.foregroundStyle(style.color)
VStack(alignment: .leading, spacing: CasinoDesign.Spacing.xxSmall) {
Text(hint)
.font(.system(size: fontSize, weight: .medium))
.foregroundStyle(.white)
.lineLimit(1)
.minimumScaleFactor(CasinoDesign.MinScaleFactor.comfortable)
if let secondary = secondaryInfo {
Text(secondary)
.font(.system(size: fontSize - 2, weight: .regular))
.foregroundStyle(.white.opacity(CasinoDesign.Opacity.medium))
.lineLimit(1)
}
}
}
.padding(.horizontal, paddingH)
.padding(.vertical, paddingV)
.frame(minWidth: CasinoDesign.HintSize.minWidth, alignment: .leading)
.background(
Capsule()
.fill(Color.black.opacity(CasinoDesign.Opacity.heavy))
.overlay(
Capsule()
.strokeBorder(style.color.opacity(CasinoDesign.Opacity.medium), lineWidth: CasinoDesign.LineWidth.thin)
)
)
.shadow(color: .black.opacity(CasinoDesign.Opacity.medium), radius: CasinoDesign.Shadow.radiusMedium)
.accessibilityElement(children: .ignore)
.accessibilityLabel(String(localized: "Betting Hint", bundle: .module))
.accessibilityValue(hint)
}
}
// MARK: - Previews
#Preview("Neutral Hint") {
ZStack {
Color.CasinoTable.felt.ignoresSafeArea()
BettingHintView(
hint: "Banker has the lowest house edge (1.06%)",
style: .neutral
)
}
}
#Preview("Positive Hint") {
ZStack {
Color.CasinoTable.felt.ignoresSafeArea()
BettingHintView(
hint: "Bet 4x minimum",
secondaryInfo: "True count: +3",
style: .positive
)
}
}
#Preview("Negative Hint") {
ZStack {
Color.CasinoTable.felt.ignoresSafeArea()
BettingHintView(
hint: "Bet minimum",
secondaryInfo: "True count: -2",
style: .negative
)
}
}
#Preview("Streak Hint") {
ZStack {
Color.CasinoTable.felt.ignoresSafeArea()
BettingHintView(
hint: "Banker streak: 5 in a row",
secondaryInfo: "B: 58% | P: 38%",
style: .streak
)
}
}
#Preview("Pattern Hint") {
ZStack {
Color.CasinoTable.felt.ignoresSafeArea()
BettingHintView(
hint: "Choppy shoe - results alternating",
style: .pattern
)
}
}