Onboarding State Updates

This commit is contained in:
adam 2021-11-05 07:26:20 -05:00
parent 23873cc757
commit 9b46a4c9d3
3 changed files with 65 additions and 20 deletions

View File

@ -18,13 +18,18 @@ struct OnboardingStep: Equatable, Identifiable {
struct OnboardingState: Equatable { struct OnboardingState: Equatable {
var steps: IdentifiedArrayOf<OnboardingStep> = Self.onboardingSteps var steps: IdentifiedArrayOf<OnboardingStep> = Self.onboardingSteps
var index = 0 var index = 0
var offset: CGFloat = .zero
var skippedAtindex: Int? var skippedAtindex: Int?
var currentStep: OnboardingStep { steps[index] } var currentStep: OnboardingStep { steps[index] }
var skipButtonDisabled: Bool { steps.count == index + 1 } var skipButtonDisabled: Bool { steps.count == index + 1 }
var backButtonDisabled: Bool { index == 0 } var backButtonDisabled: Bool { index == 0 }
var progress: Int { ((index + 1) * 100) / (steps.count) } var progress: Int { ((index + 1) * 100) / (steps.count) }
var offset: CGFloat {
let maxOffset = CGFloat(-60)
let stepOffset = CGFloat(maxOffset / CGFloat(steps.count - 1))
guard index != 0 else { return .zero }
return stepOffset * CGFloat(index)
}
} }
enum OnboardingAction: Equatable { enum OnboardingAction: Equatable {
@ -43,14 +48,12 @@ let onboardingReducer = Reducer<OnboardingState, OnboardingAction, Void> { state
state.skippedAtindex = nil state.skippedAtindex = nil
} else { } else {
state.index -= 1 state.index -= 1
state.offset += 20.0
} }
return .none return .none
case .next: case .next:
guard state.index < state.steps.count - 1 else { return .none } guard state.index < state.steps.count - 1 else { return .none }
state.index += 1 state.index += 1
state.offset -= 20.0
return .none return .none
case .skip: case .skip:

View File

@ -19,6 +19,7 @@ struct OnboardingView: View {
.disabled(viewStore.backButtonDisabled) .disabled(viewStore.backButtonDisabled)
Spacer() Spacer()
Button("Next") { viewStore.send(.next) }
Button("Skip") { viewStore.send(.skip) } Button("Skip") { viewStore.send(.skip) }
.disabled(viewStore.skipButtonDisabled) .disabled(viewStore.skipButtonDisabled)

View File

@ -19,98 +19,139 @@ class OnboardingStoreTests: XCTestCase {
store.send(.next) { store.send(.next) {
$0.index += 1 $0.index += 1
$0.offset -= 20.0
XCTAssertFalse($0.skipButtonDisabled) XCTAssertFalse($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[1]) XCTAssertEqual($0.currentStep, $0.steps[1])
XCTAssertEqual($0.offset, -20.0)
XCTAssertEqual($0.progress, 50) XCTAssertEqual($0.progress, 50)
} }
store.send(.next) { store.send(.next) {
$0.index += 1 $0.index += 1
$0.offset -= 20.0
XCTAssertFalse($0.skipButtonDisabled) XCTAssertFalse($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[2]) XCTAssertEqual($0.currentStep, $0.steps[2])
XCTAssertEqual($0.offset, -40.0)
XCTAssertEqual($0.progress, 75) XCTAssertEqual($0.progress, 75)
} }
store.send(.next) { store.send(.next) {
$0.index += 1 $0.index += 1
$0.offset -= 20.0
XCTAssertTrue($0.skipButtonDisabled) XCTAssertTrue($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[3]) XCTAssertEqual($0.currentStep, $0.steps[3])
XCTAssertEqual($0.offset, -60.0)
XCTAssertEqual($0.progress, 100)
}
}
func testIncrementingPastTotalStepsDoesNothing() {
let store = TestStore(
initialState: OnboardingState(index: 3),
reducer: onboardingReducer,
environment: ()
)
store.send(.next) {
XCTAssertTrue($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[3])
XCTAssertEqual($0.offset, -60.0)
XCTAssertEqual($0.progress, 100)
}
store.send(.next) {
XCTAssertTrue($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[3])
XCTAssertEqual($0.offset, -60.0)
XCTAssertEqual($0.progress, 100) XCTAssertEqual($0.progress, 100)
} }
} }
func testDecrementingOnboarding() { func testDecrementingOnboarding() {
let store = TestStore( let store = TestStore(
initialState: OnboardingState( initialState: OnboardingState(index: 2),
index: 2,
offset: .zero - 20.0 - 20.0
),
reducer: onboardingReducer, reducer: onboardingReducer,
environment: () environment: ()
) )
store.send(.back) { store.send(.back) {
$0.index -= 1 $0.index -= 1
$0.offset += 20.0
XCTAssertFalse($0.skipButtonDisabled) XCTAssertFalse($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[1]) XCTAssertEqual($0.currentStep, $0.steps[1])
XCTAssertEqual($0.offset, -20.0)
XCTAssertEqual($0.progress, 50) XCTAssertEqual($0.progress, 50)
} }
store.send(.back) { store.send(.back) {
$0.index -= 1 $0.index -= 1
$0.offset += 20.0
XCTAssertFalse($0.skipButtonDisabled) XCTAssertFalse($0.skipButtonDisabled)
XCTAssertTrue($0.backButtonDisabled) XCTAssertTrue($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[0]) XCTAssertEqual($0.currentStep, $0.steps[0])
XCTAssertEqual($0.offset, 0.0)
XCTAssertEqual($0.progress, 25)
}
}
func testDecrementingPastFirstStepDoesNothing() {
let store = TestStore(
initialState: OnboardingState(),
reducer: onboardingReducer,
environment: ()
)
store.send(.back) {
XCTAssertFalse($0.skipButtonDisabled)
XCTAssertTrue($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[0])
XCTAssertEqual($0.offset, 0.0)
XCTAssertEqual($0.progress, 25)
}
store.send(.back) {
XCTAssertFalse($0.skipButtonDisabled)
XCTAssertTrue($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[0])
XCTAssertEqual($0.offset, 0.0)
XCTAssertEqual($0.progress, 25) XCTAssertEqual($0.progress, 25)
} }
} }
func testSkipOnboarding() { func testSkipOnboarding() {
let initialIndex = 1 let initialIndex = 1
let initialOffset: CGFloat = .zero - 20.0
let store = TestStore( let store = TestStore(
initialState: OnboardingState( initialState: OnboardingState(index: initialIndex),
index: initialIndex,
offset: initialOffset
),
reducer: onboardingReducer, reducer: onboardingReducer,
environment: () environment: ()
) )
store.send(.skip) { store.send(.skip) {
$0.index = $0.steps.count - 1 $0.index = $0.steps.count - 1
$0.offset = initialOffset
$0.skippedAtindex = initialIndex $0.skippedAtindex = initialIndex
XCTAssertTrue($0.skipButtonDisabled) XCTAssertTrue($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[3]) XCTAssertEqual($0.currentStep, $0.steps[3])
XCTAssertEqual($0.offset, -60.0)
XCTAssertEqual($0.progress, 100) XCTAssertEqual($0.progress, 100)
} }
store.send(.back) { store.send(.back) {
$0.skippedAtindex = nil $0.skippedAtindex = nil
$0.index = initialIndex $0.index = initialIndex
$0.offset = initialOffset
XCTAssertFalse($0.skipButtonDisabled) XCTAssertFalse($0.skipButtonDisabled)
XCTAssertFalse($0.backButtonDisabled) XCTAssertFalse($0.backButtonDisabled)
XCTAssertEqual($0.currentStep, $0.steps[1]) XCTAssertEqual($0.currentStep, $0.steps[1])
XCTAssertEqual($0.offset, -20.0)
XCTAssertEqual($0.progress, 50) XCTAssertEqual($0.progress, 50)
} }
} }