← poker-tutor
import SwiftUI
import PokerCore
import PokerSession
/// The cash app's front door: pick the blinds and how betting is limited, and sit down.
///
/// Two rows of pills rather than a picker: a picker's control is drawn by the platform and looks
/// different on each, while a pill is the button the rest of the app already uses, and reads the
/// same on a Mac, an iPhone and an Android phone. The choice is remembered by `AppState`.
struct CashSetupPanel: View {
@Environment(AppState.self) var app
@Environment(\.metrics) var metrics
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text(Copy.cashHowItWorks)
.body().foregroundStyle(Theme.dim)
.fixedSize(horizontal: false, vertical: true)
choice(Copy.cashStakesLabel) {
ForEach(CashSetup.stakesOnOffer, id: \.bigBlind) { stakes in
option("\(stakes.smallBlind)/\(stakes.bigBlind)",
selected: app.cashSetup.stakes == stakes) {
app.cashSetup.stakes = stakes
}
}
}
choice(Copy.cashStructureLabel) {
ForEach(BettingStructure.allCases, id: \.self) { structure in
option(Copy.structureName(structure), selected: app.cashSetup.structure == structure) {
app.cashSetup.structure = structure
}
}
}
Text(Copy.structureExplained(app.cashSetup.structure))
.caption().foregroundStyle(Theme.dim)
.fixedSize(horizontal: false, vertical: true)
// The ladder is a ladder of stakes here, and the player can climb it or ignore it.
Text(Copy.cashRungLine(rung: LadderStanding.stakesText(app.ladder.tier),
chosen: app.cashSetup.stakesLabel))
.caption().foregroundStyle(Theme.dim)
.fixedSize(horizontal: false, vertical: true)
PillButton(title: Copy.cashSitDownButton,
subtitle: Copy.cashOfferLine(stakes: app.cashSetup.stakesLabel,
structure: Copy.structureName(app.cashSetup.structure).lowercased(),
buyInBB: CashSetup.buyInInBigBlinds),
wide: metrics.compact) {
app.startCash()
}
Text(resultLine)
.body().foregroundStyle(Theme.dim)
.fixedSize(horizontal: false, vertical: true)
}
}
private var resultLine: String {
guard let result = app.lastCashResult else { return Copy.cashResultNone }
return Copy.cashResultLine(netBB: result.netBB, hands: result.hands,
per100: result.bbPer100, rebuys: result.rebuys)
}
private func choice<Content: View>(_ label: String, @ViewBuilder _ content: () -> Content) -> some View {
VStack(alignment: .leading, spacing: 6) {
Text(label).caption(weight: .medium).foregroundStyle(Theme.dim)
HStack(spacing: 6) { content() }
}
}
private func option(_ title: String, selected: Bool, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(title)
.font(.system(size: Theme.size(12), weight: selected ? .bold : .medium, design: .rounded))
.foregroundStyle(selected ? Theme.background : Theme.text)
.padding(.horizontal, 10)
.padding(.vertical, 7)
.background(selected ? Theme.accent : Theme.panelRaised, in: Capsule())
.overlay(Capsule().strokeBorder(selected ? Color.clear : Theme.dim.opacity(0.5), lineWidth: 1))
}
.buttonStyle(.plain)
}
}