172 lines
5.3 KiB
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
|
|
)
|
|
}
|
|
}
|
|
|