Complete native rewrite of the web-based SoliCards game as a SwiftUI multiplatform app targeting iOS 17+, iPadOS 17+, and macOS 14+. Three solitaire variants (Klondike, Spider, FreeCell) with full game rules, drag & drop, smart zoom layout, 6 themes, 4 difficulty levels, SwiftData persistence, VoiceOver accessibility, and 57 unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
80 lines
2.6 KiB
Swift
80 lines
2.6 KiB
Swift
import SwiftUI
|
|
|
|
struct NewGameSheet: View {
|
|
@State var variant: GameVariant
|
|
@State var difficulty: Difficulty
|
|
let onStart: (GameVariant, Difficulty) -> Void
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section("Game") {
|
|
Picker("Variant", selection: $variant) {
|
|
ForEach(GameVariant.allCases) { v in
|
|
Text(v.displayName).tag(v)
|
|
}
|
|
}
|
|
}
|
|
|
|
Section("Difficulty") {
|
|
Picker("Difficulty", selection: $difficulty) {
|
|
ForEach(Difficulty.allCases) { d in
|
|
Text(d.displayName).tag(d)
|
|
}
|
|
}
|
|
.pickerStyle(.segmented)
|
|
|
|
difficultyDetails
|
|
}
|
|
|
|
Section {
|
|
Button {
|
|
onStart(variant, difficulty)
|
|
} label: {
|
|
Text("Start Game")
|
|
.frame(maxWidth: .infinity)
|
|
.font(.headline)
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
.listRowBackground(Color.clear)
|
|
}
|
|
}
|
|
.navigationTitle("New Game")
|
|
#if os(iOS)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
#endif
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Cancel") { dismiss() }
|
|
}
|
|
}
|
|
}
|
|
#if os(macOS)
|
|
.frame(width: 400, height: 350)
|
|
#endif
|
|
}
|
|
|
|
private var difficultyDetails: some View {
|
|
let settings = difficulty.settings
|
|
return VStack(alignment: .leading, spacing: 6) {
|
|
if variant == .klondike {
|
|
detailRow("Draw", "\(settings.drawCount) card\(settings.drawCount == 1 ? "" : "s")")
|
|
}
|
|
detailRow("Undos", settings.maxUndos == .max ? "Unlimited" : "\(settings.maxUndos)")
|
|
detailRow("Hints", settings.hintsEnabled ? "On" : "Off")
|
|
detailRow("Score multiplier", String(format: "%.1fx", settings.scoreMultiplier))
|
|
}
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
private func detailRow(_ label: String, _ value: String) -> some View {
|
|
HStack {
|
|
Text(label)
|
|
Spacer()
|
|
Text(value).fontWeight(.medium)
|
|
}
|
|
}
|
|
}
|