diff --git a/ios/swiftui/Sources/ManagedPlayer/ManagedPlayerViewModel.swift b/ios/swiftui/Sources/ManagedPlayer/ManagedPlayerViewModel.swift index 19a488231..5d621537a 100644 --- a/ios/swiftui/Sources/ManagedPlayer/ManagedPlayerViewModel.swift +++ b/ios/swiftui/Sources/ManagedPlayer/ManagedPlayerViewModel.swift @@ -134,18 +134,16 @@ public class ManagedPlayerViewModel: ObservableObject, NativePlugin { } func next(_ state: CompletedState? = nil) async { - DispatchQueue.main.async { [weak self] in - self?.loadingState = .loading - self?.flow = nil - } - - do { - let nextState = try await self.manager.next(state) - DispatchQueue.main.async { [weak self] in - self?.handleNextState(nextState) + Task { @MainActor in + self.loadingState = .loading + self.flow = nil + + do { + let nextState = try await self.manager.next(state) + self.handleNextState(nextState) + } catch { + self.loadingState = .failed(error) } - } catch { - self.loadingState = .failed(error) } } diff --git a/ios/swiftui/Tests/ManagedPlayer/ManagedPlayerViewModelTests.swift b/ios/swiftui/Tests/ManagedPlayer/ManagedPlayerViewModelTests.swift index 8bc6696fa..f74ac7acd 100644 --- a/ios/swiftui/Tests/ManagedPlayer/ManagedPlayerViewModelTests.swift +++ b/ios/swiftui/Tests/ManagedPlayer/ManagedPlayerViewModelTests.swift @@ -84,7 +84,7 @@ class ManagedPlayerViewModelTests: XCTestCase { let viewModel = ManagedPlayerViewModel(manager: flowManager, onComplete: {_ in }) await assertPublished(AnyPublisher(viewModel.$loadingState), condition: { state in - guard + guard case .failed(let error) = state, let _ = error as? PlayerError else { return false } @@ -281,6 +281,62 @@ class ManagedPlayerViewModelTests: XCTestCase { XCTFail("Should have entered idle state") } } + + func testNextUpdatesLoadingStateOnMainNoFlows() async throws { + let model = ManagedPlayerViewModel(manager: ConstantFlowManager([], delay: 1/60), onComplete: {_ in}) + try await checkNextUpdatesLoadingStateOnMain(model: model, expectedStateChangeCount: 1) + } + + func testNextUpdatesLoadingStateOnMainOneFlow() async throws { + let model = ManagedPlayerViewModel(manager: ConstantFlowManager(["abc"], delay: 1/60), onComplete: {_ in}) + try await checkNextUpdatesLoadingStateOnMain(model: model, nextCallCount: 2, expectedStateChangeCount: 4) + } + + func testNextUpdatesLoadingStateOnMainMultipleFlows() async throws { + let model = ManagedPlayerViewModel(manager: ConstantFlowManager(["abc", "def", "ghi"], delay: 1/60), onComplete: {_ in}) + try await checkNextUpdatesLoadingStateOnMain(model: model, nextCallCount: 3, expectedStateChangeCount: 6) + } + + func testThrowingNextUpdatesLoadingStateOnMain() async throws { + let model = ManagedPlayerViewModel(manager: ThrowingFlowManager(), onComplete: {_ in}) + try await checkNextUpdatesLoadingStateOnMain(model: model, expectedStateChangeCount: 2) + } + + private func checkNextUpdatesLoadingStateOnMain(model: ManagedPlayerViewModel, nextCallCount: Int = 1, expectedStateChangeCount: Int) async throws { + let expect = (0.. NextState { + throw Errors.failed + } + + enum Errors: Error { + case failed + } + } } class TerminatingManager: FlowManager {