Skip to content

Commit

Permalink
Connecting state issue fixes
Browse files Browse the repository at this point in the history
On SDK configuration, interactor instance is created and has .none state. When Call screen is loaded, its start() method is called which executes some updates based on current interactor.state. When configure method is called before each engagement start (like we currently do in WidgetsSDK Testing app), CallViewModel.start() does nothing, because interactor.state is .none.
But when WidgesSDK is configured once (for example on the app launch), the same interactor instance is used for all subsequent engagements. When you end first engagement (Chat/Audio/Video, probably CV also), interactor.state is .ended. Then if you start new Audio/Video engagement, CallViewModel.start() calls CallViewModel.call.end() method, which breaks something and connecting state becomes infinite.
This commit fixes calling CallViewModel.call.end() on Audio/Video engagement start.
Commit also make two engagement references weak to avoid retaining it when CoreSDK already released it from memory.
The toggle (UISwitch) was added to Main screen, that provides the ability to disable/enable SDK configuration before each engagement.

MOB-2730
  • Loading branch information
Egor Egorov authored and github-review-helper committed Oct 12, 2023
1 parent 133357a commit 417bc57
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 35 deletions.
15 changes: 14 additions & 1 deletion GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,20 @@ class CallViewModel: EngagementViewModel, ViewModel {
super.start()

update(for: call.kind.value)
update(for: interactor.state)

// In the case when SDK is configured once and then
// visitor has several Audio/Video engagements in a raw,
// after ending each of them, `interactor.state` has `.ended` value,
// which causes calling `call.end()` on the start of the next
// Audio/Video engagement. That `call.end()` breaks the flow and SDK does not
// handle `connected` state properly. So we need to skip handling `.ended` state
// on the start of a new engagement.
switch interactor.state {
case .ended:
break
default:
update(for: interactor.state)
}

switch startWith {
case .engagement(let mediaType):
Expand Down
10 changes: 6 additions & 4 deletions GliaWidgets/Sources/ViewModel/EngagementViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class EngagementViewModel: CommonEngagementModel {
let alertConfiguration: AlertConfiguration
let environment: Environment
let screenShareHandler: ScreenShareHandler
// Need to keep strong reference of `activeEngagement`,
// to be able to fetch survey after ending engagement
var activeEngagement: CoreSdkClient.Engagement?

private(set) var isViewActive = ObservableValue<Bool>(with: false)
Expand Down Expand Up @@ -225,10 +227,10 @@ class EngagementViewModel: CommonEngagementModel {
}

func endSession() {
interactor.endSession {
self.engagementDelegate?(.finished)
} failure: { _ in
self.engagementDelegate?(.finished)
interactor.endSession { [weak self] in
self?.engagementDelegate?(.finished)
} failure: { [weak self] _ in
self?.engagementDelegate?(.finished)
}
self.screenShareHandler.stop(nil)
}
Expand Down
12 changes: 12 additions & 0 deletions GliaWidgetsTests/Sources/CallViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,16 @@ class CallViewModelTests: XCTestCase {

XCTAssertEqual(call.kind.value, .audio)
}

func test_startMethodDoesNotHandleInteractorStateEnded() {
let interactor: Interactor = .mock()
interactor.state = .ended(.byOperator)
let call: Call = .mock()
let viewModel: CallViewModel = .mock(interactor: interactor, call: call)

XCTAssertEqual(call.state.value, .none)
viewModel.start()

XCTAssertEqual(call.state.value, .none)
}
}
Loading

0 comments on commit 417bc57

Please sign in to comment.