← poker-tutor
// swift-tools-version: 6.0
import PackageDescription
// Android. Skip (https://skip.dev) compiles this same Swift for Android and renders the SwiftUI
// through its own stand-in. Everything Android-only below is declared when the Android tooling is
// present — `skip android build` and the Gradle project in `Android/` both set ANDROID_HOME — and
// otherwise not at all: a Mac or iPhone build fetches nothing extra, links nothing extra, and is
// the build it always was.
let android = Context.environment["ANDROID_HOME"] != nil
|| (Context.environment["TARGET_OS_ANDROID"] ?? "0") != "0"
let package = Package(
name: "PokerTutor",
platforms: [.macOS(.v14), .iOS(.v17)],
products: [
.library(name: "PokerCore", targets: ["PokerCore"]),
.library(name: "PokerAI", targets: ["PokerAI"]),
.library(name: "PokerCoach", targets: ["PokerCoach"]),
.library(name: "PokerSession", targets: ["PokerSession"]),
.library(name: "PokerUI", targets: ["PokerUI"]),
.executable(name: "pokerlab", targets: ["pokerlab"]),
.executable(name: "PokerTutorApp", targets: ["PokerTutorApp"]),
.executable(name: "PokerTutorCashApp", targets: ["PokerTutorCashApp"]),
],
dependencies: android ? [
.package(url: "https://github.com/skiptools/skip-fuse-ui.git", from: "1.0.0"),
.package(url: "https://github.com/skiptools/skip-fuse.git", from: "1.0.3"),
.package(url: "https://github.com/skiptools/skip.git", from: "1.9.8"),
.package(url: "https://github.com/skiptools/skip-av.git", from: "0.5.0"),
] : [],
targets: [
// The rules of poker. No UI, no platform dependencies — this is what the iPhone app
// will reuse untouched.
.target(name: "PokerCore"),
// The opponents: personalities, the skill dial, and what they infer about you.
.target(name: "PokerAI", dependencies: ["PokerCore"]),
// The coach: mistake detection, the leak taxonomy, and the skill rating.
.target(name: "PokerCoach", dependencies: ["PokerCore", "PokerAI"]),
// A minimal test harness. Apple's frameworks need a full Xcode install; this doesn't.
.target(name: "TestKit"),
// A sitting at a table: deals hands, runs the opponents, hands decisions to the coach.
// Owns everything the app would otherwise have to know about poker, so both the Mac and
// iPhone front ends stay skins over the same session — and so a session can be tested.
.target(name: "PokerSession", dependencies: ["PokerCore", "PokerAI", "PokerCoach"]),
// The suites. PokerUI is in here for one reason: the display settings — the palette and the
// text size — are plain values with no SwiftUI in them, and they are worth testing.
.target(name: "PokerTests", dependencies: ["PokerCore", "PokerAI", "PokerCoach", "PokerSession", "PokerUI", "TestKit"]),
// Apple's half of the subscription: the price, buying it, restoring it, and noticing when
// it renews or is refunded. Kept apart from PokerSession so that the rule about who may
// play — which is ours, and testable — never gets tangled up with StoreKit, which is
// Apple's and is not.
.target(name: "PokerStore", dependencies: ["PokerSession"]
+ (android ? [.product(name: "SkipFuse", package: "skip-fuse")] : [])),
// Every screen, for every platform. The Mac and iPhone apps are both shells around this:
// the layout adapts to the space it is given rather than being written twice.
.target(name: "PokerUI",
dependencies: ["PokerCore", "PokerAI", "PokerCoach", "PokerSession", "PokerStore"]
+ (android ? [.product(name: "SkipFuseUI", package: "skip-fuse-ui"),
.product(name: "SkipAV", package: "skip-av")] : []),
resources: [.process("Resources")],
plugins: android ? [.plugin(name: "skipstone", package: "skip")] : []),
// The Mac app: a window, and PokerUI inside it.
.executableTarget(name: "PokerTutorApp", dependencies: ["PokerUI"]),
// The Mac cash app: the same window around the same PokerUI, told it is the cash product.
.executableTarget(name: "PokerTutorCashApp", dependencies: ["PokerUI"]),
// Command-line driver: runs the tests and plays hands so the engine can be watched.
.executableTarget(name: "pokerlab", dependencies: ["PokerCore", "PokerAI", "PokerCoach", "PokerSession", "PokerTests", "TestKit"]),
]
)
// The Android app itself: a shell around PokerUI that Skip's Kotlin side can start. Declared only
// for Android builds so that Xcode and `swift build` on the Mac never see it — see `android` above.
if android {
package.products += [
.library(name: "PokerTutorAndroid", type: .dynamic, targets: ["PokerTutorAndroid"]),
]
package.targets += [
.target(name: "PokerTutorAndroid",
dependencies: ["PokerUI", .product(name: "SkipFuseUI", package: "skip-fuse-ui")],
plugins: [.plugin(name: "skipstone", package: "skip")]),
]
}