Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions ios/Sources/Setline/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class AppModel {
private(set) var document: SetlineDocument = .initial
var isLoading = true
var isOnboardingPresented = false
private(set) var isReplayingOnboarding = false
private(set) var isExistingOwnerOrientation = false
var isWorkoutPresented = false
var selectedTab = 0
var message: String?
Expand Down Expand Up @@ -97,7 +97,10 @@ final class AppModel {
} else {
document = try await store.load()
}
isOnboardingPresented = arguments.contains("--onboarding-demo")
let showsDemo = arguments.contains("--onboarding-demo")
isExistingOwnerOrientation = !showsDemo
&& SetlineOnboardingPolicy.hasExistingData(document)
isOnboardingPresented = showsDemo
|| SetlineOnboardingPolicy.shouldPresent(
document: document,
completed: UserDefaults.standard.bool(forKey: Self.onboardingCompletionKey)
Expand All @@ -112,21 +115,15 @@ final class AppModel {
}
}

static let onboardingCompletionKey = "setline.onboarding.completed.v1"
static let onboardingCompletionKey = "setline.illustrated-onboarding.seen.v1"

func completeOnboarding(openPlan: Bool = false) {
UserDefaults.standard.set(true, forKey: Self.onboardingCompletionKey)
isOnboardingPresented = false
isReplayingOnboarding = false
isExistingOwnerOrientation = false
selectedTab = openPlan ? 1 : 0
}

/// Reopens the product tour without changing the current programme or workout history.
func replayOnboarding() {
isReplayingOnboarding = true
isOnboardingPresented = true
}

private func startDemoSessionIfRequested(_ arguments: [String]) throws {
guard arguments.contains("--active-demo") || arguments.contains("--rest-demo") else { return }
guard document.activeSession == nil, let resolved = document.session() else { return }
Expand Down
7 changes: 0 additions & 7 deletions ios/Sources/Setline/SecondaryViews.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@ struct SettingsView: View {
.frame(minHeight: 48)
}
settingsSection("About") {
Button {
model.replayOnboarding()
} label: {
Label("Replay onboarding", systemImage: "sparkles")
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(minHeight: 44)
LabeledContent("Version", value: "1.0.0 (2)")
Link("Privacy", destination: URL(string: "https://setline.significanthobbies.com/privacy")!)
.frame(minHeight: 44)
Expand Down
22 changes: 13 additions & 9 deletions ios/Sources/Setline/SetlineOnboardingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import SwiftUI
enum SetlineOnboardingPolicy {
static func shouldPresent(document: SetlineDocument, completed: Bool) -> Bool {
guard !completed else { return false }
guard document.activeSession == nil, document.history.isEmpty else { return false }
guard document.templates.isEmpty, document.goals.isEmpty else { return false }
if case .custom = document.programme { return false }
return true
return document.activeSession == nil
}

static func hasExistingData(_ document: SetlineDocument) -> Bool {
if document.activeSession != nil || !document.history.isEmpty { return true }
if !document.templates.isEmpty || !document.goals.isEmpty { return true }
if case .custom = document.programme { return true }
return false
}
}

Expand Down Expand Up @@ -100,9 +104,9 @@ struct SetlineOnboardingView: View {
.background(SetlinePalette.paper)
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))

Button(model.isReplayingOnboarding ? "Review the bundled programme" : "Use the bundled programme") {
Button(model.isExistingOwnerOrientation ? "Review the bundled programme" : "Use the bundled programme") {
Task {
if !model.isReplayingOnboarding {
if !model.isExistingOwnerOrientation {
await model.selectProgramme(.bundled(.twelveWeekStrengthCardioMobility))
}
step = .preview
Expand Down Expand Up @@ -165,16 +169,16 @@ struct SetlineOnboardingView: View {
.font(.footnote)
.foregroundStyle(SetlinePalette.ink.opacity(0.68))

Button(model.isReplayingOnboarding ? "Return to Setline" : "Start this session") {
if model.isReplayingOnboarding {
Button(model.isExistingOwnerOrientation ? "Return to Setline" : "Start this session") {
if model.isExistingOwnerOrientation {
model.completeOnboarding()
} else {
Task { await model.startWorkout(preview) }
}
}
.buttonStyle(ActionSlabStyle())
.accessibilityHint(
model.isReplayingOnboarding
model.isExistingOwnerOrientation
? "Closes the onboarding tour without changing your programme"
: "Starts the real offline workout player"
)
Expand Down
9 changes: 6 additions & 3 deletions ios/Tests/SetlineTests/SetlineOnboardingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ final class SetlineOnboardingTests: XCTestCase {
XCTAssertFalse(SetlineOnboardingPolicy.shouldPresent(document: .initial, completed: true))
}

func testExistingActivityBypassesOnboarding() throws {
func testActiveWorkoutDefersIllustratedOrientation() throws {
var document = SetlineDocument.initial
let template = TwelveWeekProgramme.template(for: .lower, week: 1)
try document.startWorkout(template: template)
XCTAssertFalse(SetlineOnboardingPolicy.shouldPresent(document: document, completed: false))
XCTAssertTrue(SetlineOnboardingPolicy.hasExistingData(document))
}

func testExistingCustomProgrammeBypassesOnboarding() {
XCTAssertFalse(SetlineOnboardingPolicy.shouldPresent(document: .sample, completed: false))
func testExistingOwnerReceivesIllustratedOrientationOnceIdle() {
XCTAssertTrue(SetlineOnboardingPolicy.shouldPresent(document: .sample, completed: false))
XCTAssertTrue(SetlineOnboardingPolicy.hasExistingData(.sample))
XCTAssertFalse(SetlineOnboardingPolicy.shouldPresent(document: .sample, completed: true))
}
}
5 changes: 4 additions & 1 deletion ios/Tests/SetlineUITests/SetlineUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ final class SetlineUITests: XCTestCase {
private func launch(_ arguments: [String] = ["--ui-demo"]) -> XCUIApplication {
let app = XCUIApplication()
app.launchArguments = arguments
if !arguments.contains("--onboarding-demo") {
app.launchArguments += ["-setline.illustrated-onboarding.seen.v1", "YES"]
}
app.launch()
return app
}
Expand All @@ -22,7 +25,7 @@ final class SetlineUITests: XCTestCase {
/// must explicitly provide the completion default rather than inherit state
/// left behind by an earlier test or a developer's simulator.
private func launchFreshSettledApp() -> XCUIApplication {
launch(["--fresh-demo", "-setline.onboarding.completed.v1", "YES"])
launch(["--fresh-demo", "-setline.illustrated-onboarding.seen.v1", "YES"])
}

/// The decimal keypad has no return key, so the player supplies a Done button
Expand Down
Loading