Advertisement

← poker-tutor

Sources/PokerUI/CashViews.swift

3.9 KB Download file
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)
    }
}