Skip to content

Commit 8f18d49

Browse files
authored
[Fix]Show joining state after accepting an incoming call (#1079)
1 parent 6b78beb commit 8f18d49

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1616
- Fix label color when presenting. [#1077](https://github.com/GetStream/stream-video-swift/pull/1077)
1717
- Ensure CallKit push token updates and invalidation mutate `deviceToken` on the main actor to avoid Swift concurrency/actor-isolation issues. [#1076](https://github.com/GetStream/stream-video-swift/pull/1076)
1818
- Ensure CallKit joins keep the answer action completion alive until WebRTC has configured the audio device module. [#1081](https://github.com/GetStream/stream-video-swift/pull/1081)
19+
- Update incoming call acceptance to move `CallViewModel` into `.joining` before the call finishes entering, so the joining UI appears immediately. [#1079](https://github.com/GetStream/stream-video-swift/pull/1079)
1920

2021
# [1.43.0](https://github.com/GetStream/stream-video-swift/releases/tag/1.43.0)
2122
_February 27, 2026_

Sources/StreamVideoSwiftUI/CallViewModel.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,11 @@ open class CallViewModel: ObservableObject {
579579
do {
580580
hasAcceptedCall = true
581581
try await call.accept()
582+
583+
// Mirror `joinCall` so the incoming UI is dismissed before
584+
// `enterCall` finishes the async join flow.
585+
await MainActor.run { self.setCallingState(.joining) }
586+
582587
enterCall(
583588
call: call,
584589
callType: callType,

StreamVideoSwiftUITests/CallViewModel_Tests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright © 2026 Stream.io Inc. All rights reserved.
33
//
44

5+
import Combine
56
@testable import StreamVideo
67
@testable import StreamVideoSwiftUI
78
import StreamWebRTC
@@ -405,6 +406,34 @@ final class CallViewModel_Tests: XCTestCase, @unchecked Sendable {
405406
await assertCallingState(.inCall)
406407
}
407408

409+
func test_incomingCall_acceptCall_updatesCallingStateToJoiningBeforeInCall() async throws {
410+
// Given
411+
await prepareIncomingCallScenario()
412+
let joiningStateExpectation = expectation(
413+
description: "CallingState becomes joining"
414+
)
415+
joiningStateExpectation.assertForOverFulfill = false
416+
var cancellable: AnyCancellable?
417+
418+
// Capture the transient state because `acceptCall` continues into the
419+
// async `enterCall` flow immediately after the acceptance request.
420+
cancellable = subject.$callingState
421+
.dropFirst()
422+
.sink { state in
423+
if state == .joining {
424+
joiningStateExpectation.fulfill()
425+
}
426+
}
427+
defer { cancellable?.cancel() }
428+
429+
// When
430+
subject.acceptCall(callType: callType, callId: callId)
431+
432+
// Then
433+
await fulfillment(of: [joiningStateExpectation], timeout: defaultTimeout)
434+
await assertCallingState(.inCall)
435+
}
436+
408437
func test_incomingCall_acceptedFromSameUserElsewhere_callingStateChangesToIdle() async throws {
409438
// Given
410439
await prepareIncomingCallScenario()

0 commit comments

Comments
 (0)