122 lines
3.8 KiB
Swift
122 lines
3.8 KiB
Swift
//
|
|
// RoadMapView.swift
|
|
// Baccarat
|
|
//
|
|
// A visual history display of recent game results (Big Road style).
|
|
//
|
|
|
|
import SwiftUI
|
|
import CasinoKit
|
|
|
|
/// A simple road display showing recent results.
|
|
struct RoadMapView: View {
|
|
let results: [RoundResult]
|
|
|
|
// MARK: - Scaled Fonts (Dynamic Type)
|
|
|
|
@ScaledMetric(relativeTo: .caption2) private var historyFontSize: CGFloat = Design.BaseFontSize.small
|
|
@ScaledMetric(relativeTo: .caption2) private var dotSize: CGFloat = 22
|
|
|
|
// MARK: - Accessibility
|
|
|
|
private var historySummary: String {
|
|
if results.isEmpty {
|
|
return String(localized: "No history yet")
|
|
}
|
|
|
|
let playerWins = results.filter { $0.result == .playerWins }.count
|
|
let bankerWins = results.filter { $0.result == .bankerWins }.count
|
|
let ties = results.filter { $0.result == .tie }.count
|
|
|
|
let format = String(localized: "historySummaryFormat")
|
|
return String(format: format, results.count, playerWins, bankerWins, ties)
|
|
}
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: Design.Spacing.xSmall) {
|
|
Text("HISTORY")
|
|
.font(.system(size: historyFontSize, weight: .bold, design: .rounded))
|
|
.foregroundStyle(.white.opacity(0.6))
|
|
.tracking(1)
|
|
|
|
ScrollView(.horizontal) {
|
|
HStack(spacing: Design.Spacing.xSmall) {
|
|
ForEach(results) { result in
|
|
RoadDot(result: result.result, dotSize: dotSize)
|
|
}
|
|
}
|
|
.padding(.vertical, Design.Spacing.xSmall)
|
|
}
|
|
.scrollIndicators(.hidden)
|
|
}
|
|
.padding(.horizontal, Design.Spacing.medium)
|
|
.padding(.vertical, Design.Spacing.small)
|
|
.background(
|
|
RoundedRectangle(cornerRadius: Design.CornerRadius.small)
|
|
.fill(Color.black.opacity(Design.Opacity.light))
|
|
)
|
|
.accessibilityElement(children: .ignore)
|
|
.accessibilityLabel(String(localized: "Game history"))
|
|
.accessibilityValue(historySummary)
|
|
}
|
|
}
|
|
|
|
/// A single dot in the road display.
|
|
struct RoadDot: View {
|
|
let result: GameResult
|
|
let dotSize: CGFloat
|
|
|
|
// MARK: - Scaled Fonts (Dynamic Type)
|
|
|
|
@ScaledMetric(relativeTo: .caption2) private var labelFontSize: CGFloat = Design.BaseFontSize.small
|
|
|
|
private var color: Color {
|
|
switch result {
|
|
case .playerWins: return .blue
|
|
case .bankerWins: return .red
|
|
case .tie: return .green
|
|
}
|
|
}
|
|
|
|
private var label: String {
|
|
switch result {
|
|
case .playerWins: return "P"
|
|
case .bankerWins: return "B"
|
|
case .tie: return "T"
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
Circle()
|
|
.fill(color)
|
|
.frame(width: dotSize, height: dotSize)
|
|
|
|
Circle()
|
|
.strokeBorder(Color.white.opacity(Design.Opacity.light), lineWidth: Design.LineWidth.thin)
|
|
.frame(width: dotSize, height: dotSize)
|
|
|
|
Text(label)
|
|
.font(.system(size: labelFontSize, weight: .bold))
|
|
.foregroundStyle(.white)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ZStack {
|
|
Color.Table.preview
|
|
.ignoresSafeArea()
|
|
|
|
RoadMapView(results: [
|
|
RoundResult(result: .playerWins, playerValue: 8, bankerValue: 6),
|
|
RoundResult(result: .bankerWins, playerValue: 4, bankerValue: 7),
|
|
RoundResult(result: .tie, playerValue: 5, bankerValue: 5),
|
|
RoundResult(result: .playerWins, playerValue: 9, bankerValue: 3),
|
|
RoundResult(result: .bankerWins, playerValue: 2, bankerValue: 8)
|
|
])
|
|
.padding()
|
|
}
|
|
}
|
|
|