Basic Setup
Three actions covering the most common startup flows for TaskFlow: forced update, onboarding, and a what's new screen.
ForceUpdateAction
A .critical action that gates the entire app on a server-driven update check. execute() creates a CompletionSignal, passes it to shared state, and suspends until the signal is resolved (which in a forced-update flow only happens after the user installs the update).
import ForgeOrchestrator
struct ForceUpdateAction: SequenceAction {
let id: ActionID = "force-update"
let priority: ActionPriority = .critical
func shouldRun() async -> Bool {
// Return true if the server requires a newer app version
await UpdateService.shared.isForcedUpdateRequired()
}
func execute() async {
// Create the signal and hand it to shared state so the view can complete it.
// The force-update screen has no dismiss — users must update via the App Store.
let signal = CompletionSignal()
await MainActor.run {
TaskFlowState.shared.forceUpdateSignal = signal
TaskFlowState.shared.showForceUpdate = true
}
await signal.wait()
}
} OnboardingAction
A .high action that shows onboarding only on first launch. Guards against re-showing by checking a UserDefaults flag set by the onboarding view on completion.
import ForgeOrchestrator
struct OnboardingAction: SequenceAction {
let id: ActionID = "onboarding"
let priority: ActionPriority = .high
func shouldRun() async -> Bool {
!UserDefaults.standard.bool(forKey: "onboardingComplete")
}
func execute() async {
let signal = CompletionSignal()
await MainActor.run {
TaskFlowState.shared.onboardingSignal = signal
TaskFlowState.shared.showOnboarding = true
}
await signal.wait()
}
} WhatsNewAction
A .medium action that presents the what's new screen when the app version has changed since the last launch. The view calls signal.complete() when the user dismisses it.
import ForgeOrchestrator
struct WhatsNewAction: SequenceAction {
let id: ActionID = "whats-new"
let priority: ActionPriority = .medium
func shouldRun() async -> Bool {
let lastSeenVersion = UserDefaults.standard.string(forKey: "lastSeenVersion") ?? ""
return lastSeenVersion != AppVersion.current
}
func execute() async {
let signal = CompletionSignal()
await MainActor.run {
TaskFlowState.shared.whatsNewSignal = signal
TaskFlowState.shared.showWhatsNew = true
}
await signal.wait()
}
} Wiring It Together
Register all three actions and call evaluate() from the app entry point. register() is synchronous — only evaluate() needs await. Actions run in priority order regardless of registration order.
import SwiftUI
import ForgeOrchestrator
@main
struct TaskFlowApp: App {
@State private var orchestrator = SequenceOrchestrator()
var body: some Scene {
WindowGroup {
ContentView()
.environment(orchestrator)
.task {
// register() is @MainActor and synchronous — no await needed
orchestrator.register(ForceUpdateAction())
orchestrator.register(OnboardingAction())
orchestrator.register(WhatsNewAction())
let completed = await orchestrator.evaluate()
print("Startup completed:", completed)
}
}
}
}