diff --git a/.swiftformat b/.swiftformat index c28a6f3dd..ee7e52224 100644 --- a/.swiftformat +++ b/.swiftformat @@ -81,4 +81,4 @@ --wrapcollections before-first # Exclude paths ---exclude **/Generated,**/generated,**/protobuf,**/OpenApi +--exclude **/Generated,**/generated,**/protobuf,**/OpenApi,vendor/bundle,Pods,spm_cache,derived_data,.build diff --git a/.swiftlint.yml b/.swiftlint.yml index 8617e7d58..1334737d1 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,14 +1,16 @@ # Directory and file filters -included: - - Sources - - DemoApp - - DemoAppUIKit excluded: - Tests/SwiftLintFrameworkTests/Resources - Sources/StreamVideo/Generated - Sources/StreamVideo/OpenApi - Sources/StreamVideo/protobuf - Sources/StreamVideoSwiftUI/Generated + - DocumentationTests + - Pods + - .build + - spm_cache + - vendor/bundle + - derived_data # Custom Rules custom_rules: @@ -26,4 +28,4 @@ custom_rules: # Enabled/disabled rules only_rules: - unhandled_throwing_task - # - custom_rules \ No newline at end of file + # - custom_rules diff --git a/CHANGELOG.md b/CHANGELOG.md index a3499cf7c..ebed385ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### 🔄 Changed +# [1.34.1](https://github.com/GetStream/stream-video-swift/releases/tag/1.34.1) +_October 14, 2025_ + +### 🐞 Fixed +- An issue that was causing the speaker to toggle nonstop. [#968](https://github.com/GetStream/stream-video-swift/pull/968) + # [1.34.0](https://github.com/GetStream/stream-video-swift/releases/tag/1.34.0) _October 07, 2025_ diff --git a/CallIntent/IntentHandler.swift b/CallIntent/IntentHandler.swift index fee7cb730..5c09fa2f3 100644 --- a/CallIntent/IntentHandler.swift +++ b/CallIntent/IntentHandler.swift @@ -5,14 +5,14 @@ import Intents class IntentHandler: INExtension, INStartCallIntentHandling { - override func handler(for intent: INIntent) -> Any { - return self - } + override func handler(for intent: INIntent) -> Any { + return self + } - func handle(intent: INStartCallIntent, completion: @escaping (INStartCallIntentResponse) -> Void) { - let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartCallIntent.self)) - let response = INStartCallIntentResponse(code: .continueInApp, userActivity: userActivity) + func handle(intent: INStartCallIntent, completion: @escaping (INStartCallIntentResponse) -> Void) { + let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartCallIntent.self)) + let response = INStartCallIntentResponse(code: .continueInApp, userActivity: userActivity) - completion(response) - } + completion(response) + } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/01-basics/03-quickstart.swift b/DocumentationTests/DocumentationTests/DocumentationTests/01-basics/03-quickstart.swift index 9fc25f43d..63083f175 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/01-basics/03-quickstart.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/01-basics/03-quickstart.swift @@ -1,8 +1,12 @@ -import SwiftUI +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamVideo import StreamVideoSwiftUI +import SwiftUI -fileprivate func content() { +private func content() { container { struct VideoDemoSwiftUIApp: View { @@ -53,7 +57,7 @@ fileprivate func content() { callViewModel.startCall( callType: "default", callId: callId, - members: [/* Your list of participants goes here. */] + members: [ /* Your list of participants goes here. */ ] ) } label: { Text("Start a call") @@ -127,7 +131,7 @@ fileprivate func content() { callViewModel.startCall( callType: "default", callId: callId, - members: [/* Your list of participants goes here. */] + members: [ /* Your list of participants goes here. */ ] ) } label: { Text("Start a call") @@ -137,7 +141,5 @@ fileprivate func content() { .modifier(CallModifier(viewFactory: CustomViewFactory(), viewModel: callViewModel)) } } - } - } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/01-client-auth.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/01-client-auth.swift index 2b9aa9e1a..fd28a799c 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/01-client-auth.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/01-client-auth.swift @@ -1,6 +1,10 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamVideo -fileprivate enum First { +private enum First { static let streamVideo = StreamVideo( apiKey: apiKey, user: user, @@ -9,7 +13,7 @@ fileprivate enum First { ) } -fileprivate enum Second { +private enum Second { static let streamVideo = StreamVideo( apiKey: apiKey, user: .guest("guest"), @@ -18,7 +22,7 @@ fileprivate enum Second { ) } -fileprivate enum Third { +private enum Third { static let streamVideo = StreamVideo( apiKey: apiKey, user: .anonymous, @@ -27,7 +31,7 @@ fileprivate enum Third { ) } -fileprivate enum Fourth { +private enum Fourth { static let streamVideo = StreamVideo( apiKey: apiKey, user: user, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/02-joining-creating-calls.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/02-joining-creating-calls.swift index 113e831b0..7b484af74 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/02-joining-creating-calls.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/02-joining-creating-calls.swift @@ -1,6 +1,10 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamVideo -fileprivate func content() { +private func content() { asyncContainer { let call = streamVideo.call(callType: "default", callId: "123") let result = try await call.create() diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/03-call-and-participant-state.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/03-call-and-participant-state.swift index 93c272069..b90f0d1c4 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/03-call-and-participant-state.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/03-call-and-participant-state.swift @@ -1,8 +1,12 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamVideo import StreamVideoSwiftUI @MainActor -fileprivate func content() { +private func content() { container { let clientState = streamVideo.state let callState = call.state @@ -17,7 +21,7 @@ fileprivate func content() { } container { - let cancellable = call.state.$participants.sink { participants in + let cancellable = call.state.$participants.sink { _ in // .. } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/04-camera-and-microphone.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/04-camera-and-microphone.swift index 4a92f4356..1f6ccad3e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/04-camera-and-microphone.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/04-camera-and-microphone.swift @@ -1,8 +1,12 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamVideo import StreamVideoSwiftUI @MainActor -fileprivate func content() { +private func content() { container { let call = streamVideo.call(callType: "default", callId: "123") let camera = call.camera diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/06-querying-calls.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/06-querying-calls.swift index 51fb528f5..110dd25ce 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/06-querying-calls.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/06-querying-calls.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let filters: [String: RawJSON] = ["ended_at": .nil] let sort = [SortParamRequest.descending("created_at")] @@ -90,7 +94,7 @@ fileprivate func content() { ScrollView { LazyVStack { - ForEach(callsViewModel.calls, id: \.callId) { call in + ForEach(callsViewModel.calls, id: \.callId) { _ in CallView(viewFactory: viewFactory, viewModel: viewModel) .padding(.vertical, 4) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-dependency-injection.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-dependency-injection.swift index 60996acf6..8b98331e3 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-dependency-injection.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-dependency-injection.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { @Injected(\.streamVideo) var streamVideo @Injected(\.fonts) var fonts diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-querying-call-members.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-querying-call-members.swift index a1c9ebd30..2891528f8 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-querying-call-members.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/07-querying-call-members.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { // sorting and pagination let sort = SortParamRequest(direction: 1, field: "user_id") diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/08-permissions-and-moderation.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/08-permissions-and-moderation.swift index 2b7f52859..ce5bd3b9e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/08-permissions-and-moderation.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/08-permissions-and-moderation.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { // see if you currently have this permission. let hasPermission = call.currentUserHasCapability(.sendAudio) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/09-reactions.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/09-reactions.swift index 47bd40de1..9d72ed651 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/09-reactions.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/09-reactions.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let response = try await call.sendReaction(type: "fireworks") } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-custom-events.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-custom-events.swift index 40b8a6980..a2ce940c6 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-custom-events.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-custom-events.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let response = try await call.sendCustomEvent(["type": .string("draw"), "x": .number(10), "y": .number(20)]) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-view-slots.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-view-slots.swift index b638d9958..638e04ff1 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-view-slots.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/10-view-slots.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { class CustomViewFactory: ViewFactory { @@ -20,7 +24,6 @@ fileprivate func content() { func makeOutgoingCallView(viewModel: CallViewModel) -> some View { CustomOutgoingCallView(viewModel: viewModel) } - } } @@ -40,7 +43,6 @@ fileprivate func content() { public func makeIncomingCallView(viewModel: CallViewModel, callInfo: IncomingCall) -> some View { CustomIncomingCallView(callInfo: callInfo, viewModel: viewModel) } - } } @@ -59,7 +61,6 @@ fileprivate func content() { public func makeCallView(viewModel: CallViewModel) -> some View { CustomCallView(viewModel: viewModel) } - } } @@ -78,7 +79,6 @@ fileprivate func content() { func makeCallControlsView(viewModel: CallViewModel) -> some View { CustomCallControlsView(viewModel: viewModel) } - } } @@ -88,7 +88,7 @@ fileprivate func content() { public func makeVideoParticipantsView( viewModel: CallViewModel, availableFrame: CGRect, - onChangeTrackVisibility: @escaping @MainActor(CallParticipant, Bool) -> Void + onChangeTrackVisibility: @escaping @MainActor (CallParticipant, Bool) -> Void ) -> some View { VideoParticipantsView( viewFactory: self, @@ -97,7 +97,6 @@ fileprivate func content() { onChangeTrackVisibility: onChangeTrackVisibility ) } - } } @@ -117,11 +116,10 @@ fileprivate func content() { id: id, availableFrame: availableFrame, contentMode: contentMode, - customData: customData, + customData: customData, call: call ) } - } } @@ -129,11 +127,11 @@ fileprivate func content() { class CustomViewFactory: ViewFactory { public func makeVideoCallParticipantModifier( - participant: CallParticipant, - call: Call?, - availableFrame: CGRect, - ratio: CGFloat, - showAllInfo: Bool + participant: CallParticipant, + call: Call?, + availableFrame: CGRect, + ratio: CGFloat, + showAllInfo: Bool ) -> some ViewModifier { VideoCallParticipantModifier( participant: participant, @@ -143,7 +141,6 @@ fileprivate func content() { showAllInfo: showAllInfo ) } - } } @@ -162,7 +159,6 @@ fileprivate func content() { public func makeCallTopView(viewModel: CallViewModel) -> some View { CallTopView(viewModel: viewModel) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/11-call-lifecycle.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/11-call-lifecycle.swift index be3a1f904..7b988c6d2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/11-call-lifecycle.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/11-call-lifecycle.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { streamVideo.call(callType: "", callId: "") } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/12-call-state.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/12-call-state.swift index ee407824f..c3d30472b 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/12-call-state.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/12-call-state.swift @@ -1,34 +1,38 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import StreamVideoUIKit import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { ZStack { - if viewModel.callingState == .outgoing { - viewFactory.makeOutgoingCallView(viewModel: viewModel) - } else if viewModel.callingState == .inCall { - if !viewModel.participants.isEmpty { - if viewModel.isMinimized { - MinimizedCallView(viewModel: viewModel) - } else { - viewFactory.makeCallView(viewModel: viewModel) - } + if viewModel.callingState == .outgoing { + viewFactory.makeOutgoingCallView(viewModel: viewModel) + } else if viewModel.callingState == .inCall { + if !viewModel.participants.isEmpty { + if viewModel.isMinimized { + MinimizedCallView(viewModel: viewModel) } else { - WaitingLocalUserView(viewModel: viewModel, viewFactory: viewFactory) + viewFactory.makeCallView(viewModel: viewModel) } - } else if case let .incoming(callInfo) = viewModel.callingState { - viewFactory.makeIncomingCallView(viewModel: viewModel, callInfo: callInfo) + } else { + WaitingLocalUserView(viewModel: viewModel, viewFactory: viewFactory) } + } else if case let .incoming(callInfo) = viewModel.callingState { + viewFactory.makeIncomingCallView(viewModel: viewModel, callInfo: callInfo) } - .onReceive(viewModel.$callingState) { _ in - if viewModel.callingState == .idle || viewModel.callingState == .inCall { - utils.callSoundsPlayer.stopOngoingSound() - } + } + .onReceive(viewModel.$callingState) { _ in + if viewModel.callingState == .idle || viewModel.callingState == .inCall { + utils.callSoundsPlayer.stopOngoingSound() } + } } container { @@ -67,7 +71,7 @@ fileprivate func content() { private func listenToIncomingCalls() { callViewModel.$callingState.sink { [weak self] newState in guard let self = self else { return } - if case .incoming(_) = newState, self == self.navigationController?.topViewController { + if case .incoming = newState, self == self.navigationController?.topViewController { let next = CallViewController(viewModel: self.callViewModel) CallViewHelper.shared.add(callView: next.view) } else if newState == .idle { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/13-livestreaming.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/13-livestreaming.swift index c6dc5363e..ad3a4b3d8 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/13-livestreaming.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/13-livestreaming.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import StreamVideoUIKit import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct LivestreamApp: App { @State var streamVideo: StreamVideo @@ -81,7 +85,7 @@ fileprivate func content() { } } - if let recordings, recordings.count > 0 { + if let recordings, !recordings.isEmpty { Text("Watch recordings:") ForEach(recordings, id: \.self) { recording in Button { @@ -124,7 +128,7 @@ fileprivate func content() { GeometryReader { reader in if let first = state.participants.first(where: { hostIds.contains($0.userId) }) { VideoRendererView(id: first.id, size: reader.size) { renderer in - renderer.handleViewRendering(for: first) { size, participant in } + renderer.handleViewRendering(for: first) { _, _ in } } } else { Text("The host's video is not available") @@ -134,7 +138,7 @@ fileprivate func content() { } var hostIds: [String] { - state.members.filter { $0.role == "host" }.map(\.id) + state.members.filter { $0.role == "host" }.map(\.id) } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/14-swiftui-vs-uikit.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/14-swiftui-vs-uikit.swift index 52c8fdd77..4df554d5e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/14-swiftui-vs-uikit.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/14-swiftui-vs-uikit.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import StreamVideoUIKit import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CallView: View { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/15-migration-from-dolby.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/15-migration-from-dolby.swift index b5ae8ad14..1adb994e2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/15-migration-from-dolby.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/15-migration-from-dolby.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { final class CustomObject { private var client: StreamVideo @@ -15,9 +19,9 @@ fileprivate func content() { init() { let user = User( - id: userId, - name: "Obi-Wan Kenobi", // name and imageURL are used in the UI - imageURL: .init(string: "https://picsum.photos/120") + id: userId, + name: "Obi-Wan Kenobi", // name and imageURL are used in the UI + imageURL: .init(string: "https://picsum.photos/120") ) // Initialize Stream Video client @@ -47,7 +51,7 @@ fileprivate func content() { options: .init( members: [ .init(userId: "john_smith"), - .init(userId: "jane_doe"), + .init(userId: "jane_doe") ], custom: [ "title": .string("SwiftUI heads"), @@ -129,7 +133,7 @@ fileprivate func content() { options: .init( members: [ .init(userId: "john_smith"), - .init(userId: "jane_doe"), + .init(userId: "jane_doe") ], custom: [ "title": .string("SwiftUI heads"), @@ -165,20 +169,20 @@ fileprivate func content() { VStack { VStack { Text("\(title ?? "")") - .font(.title) - .frame(maxWidth: .infinity, alignment: .leading) - .lineLimit(1) - .padding([.bottom], 8) + .font(.title) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(1) + .padding([.bottom], 8) Text("\(description ?? "")") - .font(.body) - .frame(maxWidth: .infinity, alignment: .leading) - .lineLimit(1) - .padding([.bottom], 4) + .font(.body) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(1) + .padding([.bottom], 4) Text("\(participants.count) participants") - .font(.caption) - .frame(maxWidth: .infinity, alignment: .leading) + .font(.caption) + .frame(maxWidth: .infinity, alignment: .leading) }.padding([.leading, .trailing]) } } @@ -216,9 +220,9 @@ fileprivate func content() { var body: some View { Button { - Task { - try await microphone.toggle() - } + Task { + try await microphone.toggle() + } } label: { Image(systemName: microphone.status == .enabled ? "mic.circle" : "mic.slash.circle") .foregroundColor(microphone.status == .enabled ? .red : .primary) @@ -243,7 +247,7 @@ fileprivate func content() { var participant: CallParticipant var body: some View { - VStack{ + VStack { ZStack { Circle() .fill(participant.isSpeaking ? .green : .white) @@ -275,9 +279,9 @@ fileprivate func content() { HStack { Text("\(request.user.name) requested to \(request.permission)") Button { - Task { - try await call.grant(request: request) - } + Task { + try await call.grant(request: request) + } } label: { Label("", systemImage: "hand.thumbsup.circle").tint(.green) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/16-noise-cancellation.swift b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/16-noise-cancellation.swift index 2bcc0c910..bf2a8d282 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/16-noise-cancellation.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/03-guides/16-noise-cancellation.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo +import StreamVideoNoiseCancellation import StreamVideoSwiftUI import SwiftUI -import Combine -import StreamVideoNoiseCancellation @MainActor -fileprivate func content() { +private func content() { container { let processor = NoiseCancellationProcessor() diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/02-video-renderer.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/02-video-renderer.swift index 82bf2ddf4..d979fb2bc 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/02-video-renderer.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/02-video-renderer.swift @@ -1,18 +1,22 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI -import SwiftUI -import Combine import StreamWebRTC +import SwiftUI @MainActor -fileprivate func content() { +private func content() { viewContainer { VideoRendererView( id: id, size: availableSize, contentMode: contentMode ) { view in - view.handleViewRendering(for: participant) { size, participant in + view.handleViewRendering(for: participant) { _, _ in // handle track size update } } @@ -24,25 +28,25 @@ fileprivate func content() { func add(track: RTCVideoTrack) {} func handleViewRendering( - for participant: CallParticipant, - onTrackSizeUpdate: @escaping (CGSize, CallParticipant) -> () - ) { - if let track = participant.track { - log.debug("adding track to a view \(self)") - self.add(track: track) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { - let prev = participant.trackSize - let scale = UIScreen.main.scale - let newSize = CGSize( - width: self.bounds.size.width * scale, - height: self.bounds.size.height * scale - ) - if prev != newSize { - onTrackSizeUpdate(newSize, participant) - } + for participant: CallParticipant, + onTrackSizeUpdate: @escaping (CGSize, CallParticipant) -> Void + ) { + if let track = participant.track { + log.debug("adding track to a view \(self)") + self.add(track: track) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { + let prev = participant.trackSize + let scale = UIScreen.main.scale + let newSize = CGSize( + width: self.bounds.size.width * scale, + height: self.bounds.size.height * scale + ) + if prev != newSize { + onTrackSizeUpdate(newSize, participant) } } } + } } } @@ -138,4 +142,3 @@ fileprivate func content() { } } } - diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/03-video-theme.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/03-video-theme.swift index 0a235c2d8..fcd1b35eb 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/03-video-theme.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/03-video-theme.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { let streamBlue = UIColor(red: 0, green: 108.0 / 255.0, blue: 255.0 / 255.0, alpha: 1) var colors = Colors() diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/04-customizing-views.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/04-customizing-views.swift index 3491fe74f..31253aa3b 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/04-customizing-views.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/04-customizing-views.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { class CustomViewFactory: ViewFactory { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/05-uikit-customizations.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/05-uikit-customizations.swift index 9042a45dc..d2c1ef1e5 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/05-uikit-customizations.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/05-uikit-customizations.swift @@ -1,14 +1,18 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine +import class StreamChat.ChatChannelController +import struct StreamChatSwiftUI.ChatChannelView +import struct StreamChatSwiftUI.UnreadIndicatorView import StreamVideo import StreamVideoSwiftUI import StreamVideoUIKit import SwiftUI -import Combine -import struct StreamChatSwiftUI.ChatChannelView -import struct StreamChatSwiftUI.UnreadIndicatorView -import class StreamChat.ChatChannelController @MainActor -fileprivate func content() { +private func content() { container { class VideoWithChatViewFactory: ViewFactory { @@ -20,7 +24,6 @@ fileprivate func content() { func makeCallControlsView(viewModel: CallViewModel) -> some View { ChatCallControls(viewModel: viewModel) } - } } @@ -35,7 +38,6 @@ fileprivate func content() { let videoView = makeVideoView(with: VideoWithChatViewFactory.shared) view.embed(videoView) } - } @MainActor @@ -79,7 +81,7 @@ fileprivate func content() { private func listenToIncomingCalls() { callViewModel.$callingState.sink { [weak self] newState in guard let self = self else { return } - if case .incoming(_) = newState, self == self.navigationController?.topViewController { + if case .incoming = newState, self == self.navigationController?.topViewController { let next = CallChatViewController.makeCallChatController(with: self.callViewModel) CallViewHelper.shared.add(callView: next.view) } else if newState == .idle { @@ -126,12 +128,13 @@ fileprivate func content() { ) .overlay( chatHelper.unreadCount > 0 ? - TopRightView(content: { - UnreadIndicatorView(unreadCount: chatHelper.unreadCount) - }) - : nil + TopRightView(content: { + UnreadIndicatorView(unreadCount: chatHelper.unreadCount) + }) + : nil ) - }) + } + ) .frame(maxWidth: .infinity) Button( @@ -213,7 +216,7 @@ fileprivate func content() { .cornerRadius(16) .edgesIgnoringSafeArea(.all) ) - .onReceive(viewModel.$callParticipants, perform: { output in + .onReceive(viewModel.$callParticipants, perform: { _ in if viewModel.callParticipants.count > 1 { chatHelper.update(memberIds: Set(viewModel.callParticipants.map(\.key))) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/06-view-model.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/06-view-model.swift index 601977f6a..64f5523d4 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/06-view-model.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/06-view-model.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { Button { viewModel.startCall(callType: "default", callId: callId, members: callMembers, ring: false) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/01-call-container.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/01-call-container.swift index d5340f8c0..434bd30ca 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/01-call-container.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/01-call-container.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { @StateObject var viewModel = CallViewModel() diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/02-outgoing-call.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/02-outgoing-call.swift index 4fac5d59a..9924a63d8 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/02-outgoing-call.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/02-outgoing-call.swift @@ -1,16 +1,20 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { public var body: some View { OutgoingCallView( - outgoingCallMembers: outgoingCallMembers, + outgoingCallMembers: outgoingCallMembers, callTopView: callTopView, callControls: callControls ) @@ -24,7 +28,6 @@ fileprivate func content() { public func makeOutgoingCallView(viewModel: CallViewModel) -> some View { CustomOutgoingCallView(viewModel: viewModel) } - } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/03-incoming-call.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/03-incoming-call.swift index fcdc3c6fa..68f0967a9 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/03-incoming-call.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/03-incoming-call.swift @@ -1,22 +1,26 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var callInfo: IncomingCall public var body: some View { IncomingCallView( - callInfo: callInfo, - onCallAccepted: { _ in - // handle call accepted - }, onCallRejected: { _ in - // handle call rejected - } + callInfo: callInfo, + onCallAccepted: { _ in + // handle call accepted + }, onCallRejected: { _ in + // handle call rejected + } ) } } @@ -28,7 +32,6 @@ fileprivate func content() { public func makeIncomingCallView(viewModel: CallViewModel, callInfo: IncomingCall) -> some View { CustomIncomingCallView(viewModel: viewModel, callInfo: callInfo) } - } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/04-active-call.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/04-active-call.swift index 18e54f921..130c765b7 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/04-active-call.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/04-active-call.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var callInfo: IncomingCall @@ -39,7 +43,7 @@ fileprivate func content() { public func makeVideoParticipantsView( viewModel: CallViewModel, availableFrame: CGRect, - onChangeTrackVisibility: @escaping @MainActor(CallParticipant, Bool) -> Void + onChangeTrackVisibility: @escaping @MainActor (CallParticipant, Bool) -> Void ) -> some View { VideoParticipantsView( viewFactory: self, @@ -78,11 +82,11 @@ fileprivate func content() { class CustomViewFactory: ViewFactory { public func makeVideoCallParticipantModifier( - participant: CallParticipant, - call: Call?, - availableFrame: CGRect, - ratio: CGFloat, - showAllInfo: Bool + participant: CallParticipant, + call: Call?, + availableFrame: CGRect, + ratio: CGFloat, + showAllInfo: Bool ) -> some ViewModifier { VideoCallParticipantModifier( participant: participant, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/05-call-controls.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/05-call-controls.swift index 22033b7b4..addd30ca4 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/05-call-controls.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/05-call-controls.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var callInfo: IncomingCall diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/06-call-app-bar.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/06-call-app-bar.swift index ed89b3f1a..77de8dbce 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/06-call-app-bar.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/06-call-app-bar.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var callInfo: IncomingCall diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/07-screen-share-content.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/07-screen-share-content.swift index 3ce4ce6a2..e3a3c7a70 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/07-screen-share-content.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/07-call/07-screen-share-content.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { @MainActor func custom(screensharingSession: ScreenSharingSession) { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/01-call-participant.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/01-call-participant.swift index c6ef3eb29..1c8e80ce3 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/01-call-participant.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/01-call-participant.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { VideoCallParticipantView( participant: participant, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/02-call-participants.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/02-call-participants.swift index 8a3374eb1..6274fe41e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/02-call-participants.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/02-call-participants.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { VideoParticipantsView( viewFactory: DefaultViewFactory.shared, @@ -20,7 +24,7 @@ fileprivate func content() { public func makeVideoParticipantsView( viewModel: CallViewModel, availableFrame: CGRect, - onChangeTrackVisibility: @escaping @MainActor(CallParticipant, Bool) -> Void + onChangeTrackVisibility: @escaping @MainActor (CallParticipant, Bool) -> Void ) -> some View { CustomVideoParticipantsView( viewFactory: self, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/03-call-participants-info-menu.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/03-call-participants-info-menu.swift index ccb8b3a1f..63d359d42 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/03-call-participants-info-menu.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/03-call-participants-info-menu.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { let view = CallParticipantsInfoView(callViewModel: viewModel) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/04-local-video.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/04-local-video.swift index 917db0c00..1afaf5437 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/04-local-video.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/08-participants/04-local-video.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { LocalVideoView( viewFactory: viewFactory, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/02-sound-indicator.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/02-sound-indicator.swift index 0d3488ab7..481779c21 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/02-sound-indicator.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/02-sound-indicator.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { SoundIndicator(participant: participant) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/03-avatars.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/03-avatars.swift index c1db218eb..8a49138d2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/03-avatars.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/03-avatars.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var body: some View { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/04-connection-quality-indicator.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/04-connection-quality-indicator.swift index a76abf4cf..f11a2a85d 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/04-connection-quality-indicator.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/04-connection-quality-indicator.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { ConnectionQualityIndicator(connectionQuality: participant.connectionQuality) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/05-call-background.swift b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/05-call-background.swift index e361b7a29..5839f0d0f 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/05-call-background.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/04-ui-components/09-utility/05-call-background.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomView: View { var body: some View { @@ -14,4 +18,3 @@ fileprivate func content() { } } } - diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/02-replacing-call-controls.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/02-replacing-call-controls.swift index c7a8b9f83..0abf0df60 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/02-replacing-call-controls.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/02-replacing-call-controls.swift @@ -1,17 +1,20 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { class CustomViewFactory: ViewFactory { public func makeCallControlsView(viewModel: CallViewModel) -> some View { CustomCallControlsView(viewModel: viewModel) } - } } @@ -88,7 +91,6 @@ fileprivate func content() { .cornerRadius(24) } } - } class CustomViewFactory: ViewFactory { @@ -96,7 +98,6 @@ fileprivate func content() { func makeCallControlsView(viewModel: CallViewModel) -> some View { FBCallControlsView(viewModel: viewModel) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/03-custom-label.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/03-custom-label.swift index dac0d6b56..e75913644 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/03-custom-label.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/03-custom-label.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomParticipantModifier: ViewModifier { @@ -70,7 +74,6 @@ fileprivate func content() { showAllInfo: showAllInfo ) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/04-video-layout.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/04-video-layout.swift index f56d5db01..cb39e4757 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/04-video-layout.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/04-video-layout.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct JoinCallView: View { @@ -25,7 +29,6 @@ fileprivate func content() { } .padding() } - } struct HomeView: View { @@ -87,10 +90,9 @@ fileprivate func content() { BottomRightView { MuteIndicatorView() } - : nil + : nil ) } - } struct MuteIndicatorView: View { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/05-incoming-call.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/05-incoming-call.swift index 4c4238625..ec4c57ee2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/05-incoming-call.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/05-incoming-call.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomIncomingCallView: View { @@ -77,7 +81,6 @@ fileprivate func content() { Spacer() } .padding() - } .background(Color.white.edgesIgnoringSafeArea(.all)) } @@ -92,7 +95,6 @@ fileprivate func content() { func makeIncomingCallView(viewModel: CallViewModel, callInfo: IncomingCall) -> some View { CustomIncomingCallView(callInfo: callInfo, callViewModel: viewModel) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/06-lobby-preview.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/06-lobby-preview.swift index 99fb4d94d..0f580f177 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/06-lobby-preview.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/06-lobby-preview.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomLobbyView: View { @@ -15,15 +19,15 @@ fileprivate func content() { var callId: String var callType: String @Binding var callSettings: CallSettings - var onJoinCallTap: () -> () - var onCloseLobby: () -> () + var onJoinCallTap: () -> Void + var onCloseLobby: () -> Void public init( callId: String, callType: String, callSettings: Binding, - onJoinCallTap: @escaping () -> (), - onCloseLobby: @escaping () -> () + onJoinCallTap: @escaping () -> Void, + onCloseLobby: @escaping () -> Void ) { self.callId = callId self.callType = callType @@ -63,8 +67,8 @@ fileprivate func content() { var callId: String var callType: String @Binding var callSettings: CallSettings - var onJoinCallTap: () -> () - var onCloseLobby: () -> () + var onJoinCallTap: () -> Void + var onCloseLobby: () -> Void var body: some View { GeometryReader { reader in @@ -171,7 +175,7 @@ fileprivate func content() { MicrophoneCheckView( audioLevels: microphoneChecker.audioLevels, microphoneOn: callSettings.audioOn, - isSilent: microphoneChecker.isSilent, + isSilent: microphoneChecker.isSilent, isPinned: false ) .accessibility(identifier: "microphoneCheckView") @@ -183,7 +187,7 @@ fileprivate func content() { } private var cameraSize: CGFloat { - if viewModel.participants.count > 0 { + if !viewModel.participants.isEmpty { return availableSize.height / 2 - 64 } else { return availableSize.height / 2 @@ -244,7 +248,7 @@ fileprivate func content() { var callId: String var callType: String var callParticipants: [User] - var onJoinCallTap: () -> () + var onJoinCallTap: () -> Void var body: some View { VStack(spacing: 16) { @@ -254,7 +258,7 @@ fileprivate func content() { .streamAccessibility(value: "\(otherParticipantsCount)") if #available(iOS 14, *) { - if callParticipants.count > 0 { + if !callParticipants.isEmpty { ParticipantsInCallView( callParticipants: callParticipants ) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/07-video-fallback.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/07-video-fallback.swift index ee55e9f19..7b17832c5 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/07-video-fallback.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/07-video-fallback.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { class CustomViewFactory: ViewFactory { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/08-permission-requests.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/08-permission-requests.swift index 696e752bc..58ae8a623 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/08-permission-requests.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/08-permission-requests.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { final class CustomCallViewModel: CallViewModel { @@ -21,7 +25,11 @@ fileprivate func content() { func grantUserPermissions() async throws { guard let request = permissionRequest else { return } - let permissionRequests = request.permissions.map { PermissionRequest(permission: $0, user: request.user.toUser, requestedAt: request.createdAt) } + let permissionRequests = request.permissions.map { PermissionRequest( + permission: $0, + user: request.user.toUser, + requestedAt: request.createdAt + ) } for permissionRequest in permissionRequests { try await call?.grant(request: permissionRequest) } @@ -43,10 +51,8 @@ fileprivate func content() { }, secondaryButton: .cancel() ) - } + } } } - - } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/09-audio-volume-indicator.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/09-audio-volume-indicator.swift index ffea8c94d..71ee9068a 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/09-audio-volume-indicator.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/09-audio-volume-indicator.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { AudioVolumeIndicator( audioLevels: [0.8, 0.9, 0.7], @@ -25,7 +29,7 @@ fileprivate func content() { MicrophoneCheckView( audioLevels: microphoneChecker.audioLevels, microphoneOn: callViewModel.callSettings.audioOn, - isSilent: microphoneChecker.isSilent, + isSilent: microphoneChecker.isSilent, isPinned: false ) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/10-network-quality-indicator.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/10-network-quality-indicator.swift index 789de9a90..b433fb636 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/10-network-quality-indicator.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/10-network-quality-indicator.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { ConnectionQualityIndicator(connectionQuality: participant.connectionQuality) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/11-speaking-while-muted.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/11-speaking-while-muted.swift index c2363d9b9..dc4e47295 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/11-speaking-while-muted.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/11-speaking-while-muted.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct CustomCallView: View { @@ -18,7 +22,7 @@ fileprivate func content() { var body: some View { CallView(viewFactory: viewFactory, viewModel: viewModel) - .onReceive(viewModel.$callSettings) { callSettings in + .onReceive(viewModel.$callSettings) { _ in Task { await updateMicrophoneChecker() } } .onReceive(microphoneChecker.$audioLevels, perform: { values in @@ -35,16 +39,16 @@ fileprivate func content() { }) .overlay( mutedIndicatorShown ? - VStack { - Spacer() - Text("You are muted.") - .padding(8) - .background(Color(UIColor.systemBackground)) - .foregroundColor(colors.text) - .cornerRadius(16) - .padding() - } - : nil + VStack { + Spacer() + Text("You are muted.") + .padding(8) + .background(Color(UIColor.systemBackground)) + .foregroundColor(colors.text) + .cornerRadius(16) + .padding() + } + : nil ) } @@ -62,7 +66,6 @@ fileprivate func content() { func makeCallView(viewModel: CallViewModel) -> some View { CustomCallView(viewFactory: self, viewModel: viewModel) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/12-connection-unstable.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/12-connection-unstable.swift index 99b3c92f0..8f95c0a4e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/12-connection-unstable.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/12-connection-unstable.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { YourView() .overlay( @@ -18,7 +22,6 @@ fileprivate func content() { func makeReconnectionView(viewModel: CallViewModel) -> some View { ReconnectionView(viewModel: viewModel, viewFactory: self) } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/13-pinning-users.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/13-pinning-users.swift index 1a0f6d134..dd82541c7 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/13-pinning-users.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/13-pinning-users.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { try await call.pin(sessionId: "pinned_user_session_id") } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/14-livestream-player.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/14-livestream-player.swift index dc9b61dfb..805da8740 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/14-livestream-player.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/14-livestream-player.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { viewContainer { LivestreamPlayer(type: "livestream", id: "some_id") } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/15-long-press-to-focus.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/15-long-press-to-focus.swift index db0de81fb..322c68db2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/15-long-press-to-focus.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/15-long-press-to-focus.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { // Create the call with the callType and id let call = streamVideo.call(callType: "default", callId: "123") @@ -66,7 +70,7 @@ fileprivate func content() { id: String, availableFrame: CGRect, contentMode: UIView.ContentMode, - customData: [String : RawJSON], + customData: [String: RawJSON], call: Call? ) -> some View { DefaultViewFactory.shared.makeVideoParticipantView( @@ -79,12 +83,12 @@ fileprivate func content() { ) .longPressToFocus(availableFrame: availableFrame) { point in Task { - guard call?.state.sessionId == participant.sessionId else { return } // We are using this to only allow long pressing on our local video feed + guard call?.state.sessionId == participant.sessionId + else { return } // We are using this to only allow long pressing on our local video feed try await call?.focus(at: point) } } } - } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/16-snapshot.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/16-snapshot.swift index 05d1c0c4c..b79bcd84b 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/16-snapshot.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/16-snapshot.swift @@ -1,17 +1,21 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import AVFoundation +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import AVFoundation @MainActor -fileprivate func content() { +private func content() { viewContainer { YourHostView() .snapshot( trigger: snapshotTrigger, - snapshotHandler: { snapshot in + snapshotHandler: { _ in // Further processing ... } ) @@ -53,7 +57,6 @@ fileprivate func content() { } icon: { Image(systemName: "circle.inset.filled") } - } } } @@ -65,7 +68,7 @@ fileprivate func content() { func makeVideoParticipantsView( viewModel: CallViewModel, availableFrame: CGRect, - onChangeTrackVisibility: @escaping @MainActor(CallParticipant, Bool) -> Void + onChangeTrackVisibility: @escaping @MainActor (CallParticipant, Bool) -> Void ) -> some View { DefaultViewFactory.shared.makeVideoParticipantsView( viewModel: viewModel, @@ -262,7 +265,7 @@ fileprivate func content() { Task { guard await state.isCapturingVideoFrame else { return } - if let imageBuffer = sampleBuffer.imageBuffer { + if let imageBuffer = sampleBuffer.imageBuffer { let ciImage = CIImage(cvPixelBuffer: imageBuffer) if let data = UIImage(ciImage: ciImage).jpegData(compressionQuality: 1) { await sendImageData(data) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/17-camera-zoom.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/17-camera-zoom.swift index f9766ad9f..076f9b86d 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/17-camera-zoom.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/17-camera-zoom.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import AVFoundation +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import AVFoundation @MainActor -fileprivate func content() { +private func content() { asyncContainer { try await call.zoom(by: 1.5) } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/18-call-quality-rating.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/18-call-quality-rating.swift index e2d4965f0..64783fb00 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/18-call-quality-rating.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/18-call-quality-rating.swift @@ -1,18 +1,22 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import AVFoundation +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import AVFoundation @MainActor -fileprivate func content() { +private func content() { asyncContainer { try await call.collectUserFeedback( rating: rating, // a rating grade from 1 - 5, reason: "it worked great!", // the main feedback custom: [ - // ... any extra properties that you wish to collect + // ... any extra properties that you wish to collect "callWasAwesome": .bool(true) ] ) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/19-transcriptions.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/19-transcriptions.swift index 93e129d60..7221681e8 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/19-transcriptions.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/19-transcriptions.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import AVFoundation +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import AVFoundation @MainActor -fileprivate func content() { +private func content() { container { struct TranscriptionButtonView: View { @@ -41,8 +45,8 @@ fileprivate func content() { } icon: { Image( systemName: isTranscribing - ? "captions.bubble.fill" - : "captions.bubble" + ? "captions.bubble.fill" + : "captions.bubble" ) } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/20-noise-cancellation.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/20-noise-cancellation.swift index 0abfe992a..72388f129 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/20-noise-cancellation.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/20-noise-cancellation.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { struct NoiseCancellationButtonView: View { @@ -21,7 +25,8 @@ fileprivate func content() { } else { self.isNoiseCancellationAvailable = false } - self.isActive = streamVideo.videoConfig.noiseCancellationFilter?.id == streamVideo.videoConfig.audioProcessingModule.activeAudioFilter?.id + self.isActive = streamVideo.videoConfig.noiseCancellationFilter?.id == streamVideo.videoConfig.audioProcessingModule + .activeAudioFilter?.id } var body: some View { @@ -42,8 +47,8 @@ fileprivate func content() { } icon: { Image( systemName: isActive - ? "waveform.path.ecg" - : "waveform.path" + ? "waveform.path.ecg" + : "waveform.path" ) } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/22-manual-quality-selection.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/22-manual-quality-selection.swift index d9b840cca..42fce0e3f 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/22-manual-quality-selection.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/22-manual-quality-selection.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { // Set all incoming videos to a low resolution await call.setIncomingVideoQualitySettings( diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/23-network-disruption.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/23-network-disruption.swift index 346f7f619..c6a50962e 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/23-network-disruption.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/23-network-disruption.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { let call = streamVideo.call(callType: "default", callId: callId) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/24-closed-captions.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/24-closed-captions.swift index 82cbdfe58..54deab2c6 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/24-closed-captions.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/24-closed-captions.swift @@ -1,16 +1,20 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { - try await call.startClosedCaptions(); // start closed captions + try await call.startClosedCaptions() // start closed captions } asyncContainer { - try await call.stopClosedCaptions(); // stop closed captions + try await call.stopClosedCaptions() // stop closed captions } container { @@ -69,8 +73,8 @@ fileprivate func content() { init(call: Call) { self.call = call areClosedCaptionsAvailable = (call.state.settings?.transcription.closedCaptionMode ?? .disabled) != .disabled - && call.currentUserHasCapability(.startClosedCaptionsCall) == true - && call.currentUserHasCapability(.stopClosedCaptionsCall) == true + && call.currentUserHasCapability(.startClosedCaptionsCall) == true + && call.currentUserHasCapability(.stopClosedCaptionsCall) == true isCaptioning = call.state.captioning == true } @@ -78,25 +82,25 @@ fileprivate func content() { Group { if areClosedCaptionsAvailable { Button { - Task { - do { - if isCaptioning { - try await call.stopClosedCaptions() - } else { - try await call.startClosedCaptions() - } - } catch { - log.error(error) + Task { + do { + if isCaptioning { + try await call.stopClosedCaptions() + } else { + try await call.startClosedCaptions() } + } catch { + log.error(error) } + } } label: { Label { Text(isCaptioning ? "Disable Closed Captions" : "Closed Captions") } icon: { Image( systemName: isCaptioning - ? "captions.bubble.fill" - : "captions.bubble" + ? "captions.bubble.fill" + : "captions.bubble" ) } } @@ -120,7 +124,7 @@ fileprivate func content() { closedCaptionMode: .available, mode: .available ) - ); + ) } asyncContainer { diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/25-incoming-video-state.swift b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/25-incoming-video-state.swift index 4eee15da3..577a9f8a4 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/25-incoming-video-state.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/05-ui-cookbook/25-incoming-video-state.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let call = streamVideo.call(callType: "default", callId: "my-call-id") await call.disableClientCapabilities([.subscriberVideoPause]) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/00-ringing.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/00-ringing.swift index 1c10ab7f5..580e67a6f 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/00-ringing.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/00-ringing.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let call = streamVideo.call(callType: "default", callId: callId) let callResponse = try await call.create(members: members, ring: true) diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/01-deeplinking.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/01-deeplinking.swift index 242f8d8d8..6bffaec12 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/01-deeplinking.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/01-deeplinking.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { YourView() .onOpenURL { url in diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/02-push-notifications.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/02-push-notifications.swift index c31ffda3e..568f7a8e6 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/02-push-notifications.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/02-push-notifications.swift @@ -1,14 +1,18 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import CallKit +import Combine +import PushKit import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import CallKit -import PushKit -typealias VoIPPushHandler = ((PKPushPayload, PKPushType, () -> Void)) -> () +typealias VoIPPushHandler = ((PKPushPayload, PKPushType, () -> Void)) -> Void @MainActor -fileprivate func content() { +private func content() { container { class VoIPPushService: NSObject, PKPushRegistryDelegate { @@ -78,25 +82,25 @@ fileprivate func content() { private init() {} func registerForIncomingCalls() { - #if targetEnvironment(simulator) + #if targetEnvironment(simulator) log.info("CallKit notifications not working on a simulator") - #else + #else voIPPushService.registerForVoIPPushes() - #endif + #endif } private func unregisterForIncomingCalls() { - #if targetEnvironment(simulator) + #if targetEnvironment(simulator) log.info("CallKit notifications not working on a simulator") - #else + #else voIPPushService.unregisterForVoIPPushes() - #endif + #endif } private func makeVoIPPushService() -> VoIPPushService { let defaultCallText = "Unknown Caller" - return .init(voIPTokenHandler: AppState.shared.unsecureRepository) { [weak self] payload, type, completion in + return .init(voIPTokenHandler: AppState.shared.unsecureRepository) { [weak self] payload, _, completion in guard let self = self else { completion() return diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/03-callkit-integration.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/03-callkit-integration.swift index 42e5fe695..df3080a39 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/03-callkit-integration.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/03-callkit-integration.swift @@ -1,18 +1,15 @@ // -// 03-callkit-integration.swift -// DocumentationTests -// -// Created by Ilias Pavlidakis on 29/1/24. +// Copyright © 2025 Stream.io Inc. All rights reserved. // +import Combine +import Intents import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import Intents @MainActor -fileprivate func content() { +private func content() { container { @Injected(\.callKitAdapter) var callKitAdapter @@ -61,12 +58,12 @@ fileprivate func content() { @Injected(\.sounds) var sounds var body: some View { EmptyView() // Your content goes here. - .onAppear { - // Here we register for incomingCalls and provide - // a logo as we did on the previous example - // Provide the ringtone to use when a CallKit call is ringing - callKitAdapter.ringtoneSound = sounds.incomingCallSound.fileName - } + .onAppear { + // Here we register for incomingCalls and provide + // a logo as we did on the previous example + // Provide the ringtone to use when a CallKit call is ringing + callKitAdapter.ringtoneSound = sounds.incomingCallSound.fileName + } } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/04-screensharing.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/04-screensharing.swift index 6a0c18930..8f3894b3b 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/04-screensharing.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/04-screensharing.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { Task { let call = streamVideo.call(callType: "default", callId: "123") @@ -36,9 +40,9 @@ fileprivate func content() { class CustomViewFactory: ViewFactory { func makeScreenSharingView( - viewModel: CallViewModel, - screensharingSession: ScreenSharingSession, - availableFrame: CGRect + viewModel: CallViewModel, + screensharingSession: ScreenSharingSession, + availableFrame: CGRect ) -> some View { CustomScreenSharingView( viewModel: viewModel, diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-picture-in-picture.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-picture-in-picture.swift index f929e140f..5ad0a3626 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-picture-in-picture.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-picture-in-picture.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { final class MyViewModel { @Injected(\.pictureInPictureAdapter) var pictureInPictureAdapter diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-proximity-policies.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-proximity-policies.swift index 7994de0cb..826205dd2 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-proximity-policies.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/05-proximity-policies.swift @@ -1,17 +1,14 @@ // -// 05-proximity-policies.swift -// DocumentationTests -// -// Created by Ilias Pavlidakis on 30/4/25. +// Copyright © 2025 Stream.io Inc. All rights reserved. // +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { container { let call = streamVideo.call(callType: "default", callId: "chat-123") let policy = VideoProximityPolicy() diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/06-apply-video-filters.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/06-apply-video-filters.swift index 00fd48fa0..f94aeb033 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/06-apply-video-filters.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/06-apply-video-filters.swift @@ -1,13 +1,17 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import CoreImage import Foundation import StreamVideo import StreamVideoSwiftUI -import CoreImage +import StreamWebRTC import SwiftUI import Vision -import StreamWebRTC @MainActor -fileprivate func content() { +private func content() { container { let sepia: VideoFilter = { let sepia = VideoFilter(id: "sepia", name: "Sepia") { input in @@ -37,7 +41,7 @@ fileprivate func content() { videoFilters: FiltersService.supportedFilters ), // highlight-end - tokenProvider: { result in + tokenProvider: { _ in // Unrelated code skipped. Check repository for complete code: // https://github.com/GetStream/stream-video-ios-examples/blob/main/VideoWithChat/VideoWithChat/StreamWrapper.swift } @@ -103,7 +107,6 @@ fileprivate func content() { .background(filtersService.selectedFilter?.id == filter.id ? Color.blue : Color.gray) /* more modifiers */ } - } } } @@ -116,7 +119,7 @@ fileprivate func content() { container { func detectFaces(image: CIImage) async throws -> CGRect { return try await withCheckedThrowingContinuation { continuation in - let detectFaceRequest = VNDetectFaceRectanglesRequest { (request, error) in + let detectFaceRequest = VNDetectFaceRectanglesRequest { (request, _) in if let result = request.results?.first as? VNFaceObservation { continuation.resume(returning: result.boundingBox) } else { @@ -141,7 +144,7 @@ fileprivate func content() { format.scale = 1 format.opaque = true let renderer = UIGraphicsImageRenderer(size: size, format: format) - return renderer.image { context in + return renderer.image { _ in image.draw(in: CGRect(origin: CGPoint.zero, size: size)) logo.draw(in: inRect) } @@ -234,7 +237,8 @@ fileprivate func content() { for j in 0..= 0 && shiftedIndex < frameSize && originalIndex >= 0 && originalIndex < buffer.frames { + if shiftedIndex >= 0 && shiftedIndex < frameSize && originalIndex >= 0 && originalIndex < buffer + .frames { outputFrame[shiftedIndex] = channelBuffer[originalIndex] } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/08-recording.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/08-recording.swift index 01a260d85..7fca571ea 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/08-recording.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/08-recording.swift @@ -1,11 +1,15 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import AVKit +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine -import AVKit @MainActor -fileprivate func content() { +private func content() { container { func startRecording() { Task { @@ -27,14 +31,14 @@ fileprivate func content() { Task { for await event in call.subscribe() { switch event { - case .typeCallRecordingStartedEvent(let recordingStartedEvent): - log.debug("received an event \(recordingStartedEvent)") - /* handle recording event */ - case .typeCallRecordingStoppedEvent(let recordingStoppedEvent): - log.debug("received an event \(recordingStoppedEvent)") - /* handle recording event */ - default: - break + case .typeCallRecordingStartedEvent(let recordingStartedEvent): + log.debug("received an event \(recordingStartedEvent)") + /* handle recording event */ + case .typeCallRecordingStoppedEvent(let recordingStoppedEvent): + log.debug("received an event \(recordingStoppedEvent)") + /* handle recording event */ + default: + break } } } @@ -62,7 +66,7 @@ fileprivate func content() { var body: some View { Group { if let url = URL(string: recording.url) { - VideoPlayer(player: AVPlayer(url: url)) + VideoPlayer(player: AVPlayer(url: url)) } else { Text("Video can't be loaded") } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/09-broadcasting.swift b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/09-broadcasting.swift index 7748bf8a4..40e097549 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/09-broadcasting.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/06-advanced/09-broadcasting.swift @@ -1,10 +1,14 @@ +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + +import Combine import StreamVideo import StreamVideoSwiftUI import SwiftUI -import Combine @MainActor -fileprivate func content() { +private func content() { asyncContainer { let call = streamVideo.call(callType: .default, callId: callId) Task { @@ -23,14 +27,14 @@ fileprivate func content() { asyncContainer { for await event in call.subscribe() { switch event { - case .typeCallHLSBroadcastingStartedEvent(let broadcastingStartedEvent): - log.debug("received an event \(broadcastingStartedEvent)") - /* handle recording event */ - case .typeCallHLSBroadcastingStoppedEvent(let broadcastingStoppedEvent): - log.debug("received an event \(broadcastingStoppedEvent)") - /* handle recording event */ - default: - break + case .typeCallHLSBroadcastingStartedEvent(let broadcastingStartedEvent): + log.debug("received an event \(broadcastingStartedEvent)") + /* handle recording event */ + case .typeCallHLSBroadcastingStoppedEvent(let broadcastingStoppedEvent): + log.debug("received an event \(broadcastingStoppedEvent)") + /* handle recording event */ + default: + break } } } diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/ChatGloballyUsedVariables.swift b/DocumentationTests/DocumentationTests/DocumentationTests/ChatGloballyUsedVariables.swift index 1ac4b0d41..3c1f89ac8 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/ChatGloballyUsedVariables.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/ChatGloballyUsedVariables.swift @@ -1,5 +1,9 @@ -import StreamChatSwiftUI +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import StreamChat +import StreamChatSwiftUI final class ChatViewFactory: ViewFactory { var chatClient: ChatClient diff --git a/DocumentationTests/DocumentationTests/DocumentationTests/GloballyUsedVariables.swift b/DocumentationTests/DocumentationTests/DocumentationTests/GloballyUsedVariables.swift index e4cf0386f..57c4bf71c 100644 --- a/DocumentationTests/DocumentationTests/DocumentationTests/GloballyUsedVariables.swift +++ b/DocumentationTests/DocumentationTests/DocumentationTests/GloballyUsedVariables.swift @@ -1,9 +1,13 @@ -import StreamVideo -import StreamVideoSwiftUI -import SwiftUI +// +// Copyright © 2025 Stream.io Inc. All rights reserved. +// + import Combine import CoreImage +import StreamVideo +import StreamVideoSwiftUI import StreamWebRTC +import SwiftUI var apiKey = "" var user = User(id: "") @@ -44,7 +48,7 @@ var contentMode = UIView.ContentMode.scaleAspectFit var id = "" var customData = [String: RawJSON]() var ratio: CGFloat = 0 -var onChangeTrackVisibility: @MainActor(CallParticipant, Bool) -> Void = { _, _ in } +var onChangeTrackVisibility: @MainActor (CallParticipant, Bool) -> Void = { _, _ in } var orientation: UIInterfaceOrientation = .unknown var localParticipant = participant var reader: GeometryProxy! @@ -81,9 +85,11 @@ extension UserCredentials { class CustomType { // your custom logic here } + struct CustomInjectionKey: InjectionKey { static var currentValue: CustomType = CustomType() } + extension InjectedValues { /// Provides access to the `CustomType` instance in the views and view models. var customType: CustomType { @@ -100,6 +106,7 @@ final class CustomViewFactory: ViewFactory {} final class VideoWithChatViewFactory: ViewFactory { static let shared = VideoWithChatViewFactory() } + struct YourRootView: View { @ViewBuilder var body: some View { EmptyView() } } var outgoingCallMembers = [Member]() @MainActor var callControls = CallControlsView(viewModel: viewModel) @@ -249,9 +256,7 @@ final class AppState: ObservableObject { } final class UnsecureRepository: VoIPTokenHandler { - func save(voIPPushToken: String?) { - - } + func save(voIPPushToken: String?) {} func currentVoIPPushToken() -> String? { nil @@ -277,7 +282,6 @@ protocol VoIPTokenHandler { func save(voIPPushToken: String?) func currentVoIPPushToken() -> String? - } final class CallKitService { @@ -297,6 +301,7 @@ final class StreamSnapshotTrigger: SnapshotTriggering { func capture() {} } + var snapshotTrigger = StreamSnapshotTrigger() /// Provides the default value of the `StreamSnapshotTrigger` class. struct StreamSnapshotTriggerKey: InjectionKey { @@ -315,6 +320,7 @@ extension InjectedValues { } } } + final class SnapshotViewModel: ObservableObject { @Published var toast: Toast? } @@ -351,7 +357,7 @@ final class RobotVoiceFilter: AudioFilter { let id: String = "" let pitchShift: Float - init(pitchShift: Float) {self.pitchShift = pitchShift} + init(pitchShift: Float) { self.pitchShift = pitchShift } func applyEffect(to audioBuffer: inout RTCAudioBuffer) {} } @@ -359,8 +365,8 @@ let uiImage = UIImage() let noiseCancellationFilter = NoiseCancellationFilter( name: "noise-cancellation", - initialize: { _, _ in}, - process: { _, _ , _, _ in }, + initialize: { _, _ in }, + process: { _, _, _, _ in }, release: {} ) @@ -426,9 +432,10 @@ var otherParticipant = CallParticipant( pausedTracks: [] ) -final class UserManager { +enum UserManager { struct AppUser { var isPremium: Bool } + static var currentUser: AppUser? } diff --git a/Scripts/GenerateSPMFileLists.swift b/Scripts/GenerateSPMFileLists.swift index ccdac1743..2debc37b2 100755 --- a/Scripts/GenerateSPMFileLists.swift +++ b/Scripts/GenerateSPMFileLists.swift @@ -1,5 +1,5 @@ // -// Copyright © 2021 Stream.io Inc. All rights reserved. +// Copyright © 2025 Stream.io Inc. All rights reserved. // // This script is used to generate list of excluded source files for StreamChat and StreamChatUI in Package.swift. @@ -34,7 +34,7 @@ func sourceFileList(at url: URL) -> [String] { let basePathRange = path.range(of: url.path + "/")! return String(path[basePathRange.upperBound...]) } - .filter { $0.hasSuffix("_Tests.swift") || $0.hasSuffix("_Mock.swift") || $0.contains("__Snapshots__")} + .filter { $0.hasSuffix("_Tests.swift") || $0.hasSuffix("_Mock.swift") || $0.contains("__Snapshots__") } return sourceFiles } @@ -59,8 +59,6 @@ newGeneratedContent += "] }\n" newGeneratedContent += "\n" - - // StreamChatUI excluded source files let streamChatUIExcludedFiles = sourceFileList(at: URL(string: "Sources/StreamChatUI")!) newGeneratedContent += "var streamChatUIFilesExcluded: [String] { [\n" diff --git a/Sources/StreamVideo/Generated/SystemEnvironment+Version.swift b/Sources/StreamVideo/Generated/SystemEnvironment+Version.swift index c70af112c..16f69e86f 100644 --- a/Sources/StreamVideo/Generated/SystemEnvironment+Version.swift +++ b/Sources/StreamVideo/Generated/SystemEnvironment+Version.swift @@ -7,7 +7,7 @@ import Foundation extension SystemEnvironment { /// A Stream Video version. - public static let version: String = "1.34.0" + public static let version: String = "1.34.1" /// The WebRTC version. public static let webRTCVersion: String = "137.0.41" } diff --git a/Sources/StreamVideo/Info.plist b/Sources/StreamVideo/Info.plist index fa30752ad..2a735cd3a 100644 --- a/Sources/StreamVideo/Info.plist +++ b/Sources/StreamVideo/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.34.0 + 1.34.1 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/Sources/StreamVideo/Utils/AudioSession/CallAudioSession.swift b/Sources/StreamVideo/Utils/AudioSession/CallAudioSession.swift index 7d84fe18e..f613ea5bc 100644 --- a/Sources/StreamVideo/Utils/AudioSession/CallAudioSession.swift +++ b/Sources/StreamVideo/Utils/AudioSession/CallAudioSession.swift @@ -46,12 +46,6 @@ final class CallAudioSession: @unchecked Sendable { self.delegate = delegate self.statsAdapter = statsAdapter - interruptionEffect = .init(audioStore) - routeChangeEffect = .init( - audioStore, - callSettingsPublisher: callSettingsPublisher, - delegate: delegate - ) Publishers .CombineLatest(callSettingsPublisher, ownCapabilitiesPublisher) @@ -77,6 +71,13 @@ final class CallAudioSession: @unchecked Sendable { audioStore.restartAudioSession() } + interruptionEffect = .init(audioStore) + routeChangeEffect = .init( + audioStore, + callSettingsPublisher: callSettingsPublisher, + delegate: delegate + ) + statsAdapter?.trace(.init(audioSession: traceRepresentation)) } @@ -188,7 +189,7 @@ final class CallAudioSession: @unchecked Sendable { private func initialAudioSessionConfiguration() { let state = audioStore.state let requiresCategoryUpdate = state.category != .playAndRecord - let requiresModeUpdate = state.mode != .voiceChat && state.mode != .videoChat + let requiresModeUpdate = state.mode != .voiceChat guard requiresCategoryUpdate || requiresModeUpdate else { log.info( diff --git a/Sources/StreamVideo/Utils/AudioSession/Extensions/AVAudioSession.CategoryOptions+Convenience.swift b/Sources/StreamVideo/Utils/AudioSession/Extensions/AVAudioSession.CategoryOptions+Convenience.swift index a12e7d730..7f14fc7c9 100644 --- a/Sources/StreamVideo/Utils/AudioSession/Extensions/AVAudioSession.CategoryOptions+Convenience.swift +++ b/Sources/StreamVideo/Utils/AudioSession/Extensions/AVAudioSession.CategoryOptions+Convenience.swift @@ -13,19 +13,10 @@ extension AVAudioSession.CategoryOptions { speakerOn: Bool, appIsInForeground: Bool ) -> AVAudioSession.CategoryOptions { - var result: AVAudioSession.CategoryOptions = [ - .allowBluetooth + [ + .allowBluetooth, + .allowBluetoothA2DP ] - - /// - Note:We only add the `defaultToSpeaker` if the following are true: - /// - It's required (speakerOn = true) - /// - The app is foregrounded. The reason is that while in CallKit port overrides are being treated - /// as hard overrides and stop CallKit Speaker button from allowing the user to toggle it off. - if videoOn == false, speakerOn == true, appIsInForeground == true { - result.insert(.defaultToSpeaker) - } - - return result } /// Category options for playback. diff --git a/Sources/StreamVideo/Utils/AudioSession/Policies/DefaultAudioSessionPolicy.swift b/Sources/StreamVideo/Utils/AudioSession/Policies/DefaultAudioSessionPolicy.swift index 85f1674eb..27476d9ef 100644 --- a/Sources/StreamVideo/Utils/AudioSession/Policies/DefaultAudioSessionPolicy.swift +++ b/Sources/StreamVideo/Utils/AudioSession/Policies/DefaultAudioSessionPolicy.swift @@ -23,32 +23,17 @@ public struct DefaultAudioSessionPolicy: AudioSessionPolicy { for callSettings: CallSettings, ownCapabilities: Set ) -> AudioSessionConfiguration { - guard applicationStateAdapter.state == .foreground else { - return .init( - isActive: callSettings.audioOutputOn, - category: .playAndRecord, - mode: callSettings.videoOn ? .videoChat : .voiceChat, - options: .playAndRecord( - videoOn: callSettings.videoOn, - speakerOn: callSettings.speakerOn, - appIsInForeground: false - ), - overrideOutputAudioPort: callSettings.speakerOn - ? .speaker - : AVAudioSession.PortOverride.none - ) - } - - return .init( + .init( isActive: callSettings.audioOutputOn, category: .playAndRecord, - mode: callSettings.videoOn && callSettings.speakerOn ? .videoChat : .voiceChat, - options: .playAndRecord( - videoOn: callSettings.videoOn, - speakerOn: callSettings.speakerOn, - appIsInForeground: true - ), - overrideOutputAudioPort: callSettings.speakerOn ? .speaker : AVAudioSession.PortOverride.none + mode: .voiceChat, + options: [ + .allowBluetooth, + .allowBluetoothA2DP + ], + overrideOutputAudioPort: callSettings.speakerOn + ? .speaker + : AVAudioSession.PortOverride.none ) } } diff --git a/Sources/StreamVideo/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicy.swift b/Sources/StreamVideo/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicy.swift index c9995ef1c..061808121 100644 --- a/Sources/StreamVideo/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicy.swift +++ b/Sources/StreamVideo/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicy.swift @@ -55,7 +55,7 @@ public struct OwnCapabilitiesAudioSessionPolicy: AudioSessionPolicy { : .playback let mode: AVAudioSession.Mode = category == .playAndRecord - ? callSettings.videoOn && callSettings.speakerOn ? .videoChat : .voiceChat + ? .voiceChat : .default let categoryOptions: AVAudioSession.CategoryOptions = category == .playAndRecord diff --git a/Sources/StreamVideo/Utils/AudioSession/Protocols/AVAudioSessionProtocol.swift b/Sources/StreamVideo/Utils/AudioSession/Protocols/AVAudioSessionProtocol.swift index 07b126904..7f51fcf4a 100644 --- a/Sources/StreamVideo/Utils/AudioSession/Protocols/AVAudioSessionProtocol.swift +++ b/Sources/StreamVideo/Utils/AudioSession/Protocols/AVAudioSessionProtocol.swift @@ -10,7 +10,7 @@ protocol AVAudioSessionProtocol { /// Configures the audio session category and options. /// - Parameters: /// - category: The audio category (e.g., `.playAndRecord`). - /// - mode: The audio mode (e.g., `.videoChat`). + /// - mode: The audio mode (e.g., `.voiceChat`). /// - categoryOptions: The options for the category (e.g., `.allowBluetooth`). /// - Throws: An error if setting the category fails. func setCategory( diff --git a/Sources/StreamVideo/Utils/AudioSession/RTCAudioStore/Effects/RTCAudioStore+RouteChangeEffect.swift b/Sources/StreamVideo/Utils/AudioSession/RTCAudioStore/Effects/RTCAudioStore+RouteChangeEffect.swift index 420484d43..7876c70ac 100644 --- a/Sources/StreamVideo/Utils/AudioSession/RTCAudioStore/Effects/RTCAudioStore+RouteChangeEffect.swift +++ b/Sources/StreamVideo/Utils/AudioSession/RTCAudioStore/Effects/RTCAudioStore+RouteChangeEffect.swift @@ -48,6 +48,7 @@ extension RTCAudioStore { callSettingsCancellable = callSettingsPublisher .removeDuplicates() + .dropFirst() // We drop the first one as we allow on init the CallAudioSession to configure as expected. .sink { [weak self] in self?.activeCallSettings = $0 } session.add(self) } diff --git a/Sources/StreamVideo/WebRTC/v2/WebRTCAuthenticator.swift b/Sources/StreamVideo/WebRTC/v2/WebRTCAuthenticator.swift index b7c550369..c4a481884 100644 --- a/Sources/StreamVideo/WebRTC/v2/WebRTCAuthenticator.swift +++ b/Sources/StreamVideo/WebRTC/v2/WebRTCAuthenticator.swift @@ -98,6 +98,8 @@ struct WebRTCAuthenticator: WebRTCAuthenticating { return result }() + log.debug("CallSettings when joining speakerOn:\(callSettings.speakerOn)", subsystems: .webRTC) + await coordinator .stateAdapter .enqueueCallSettings { _ in callSettings } diff --git a/Sources/StreamVideoSwiftUI/Info.plist b/Sources/StreamVideoSwiftUI/Info.plist index fa30752ad..2a735cd3a 100644 --- a/Sources/StreamVideoSwiftUI/Info.plist +++ b/Sources/StreamVideoSwiftUI/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.34.0 + 1.34.1 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/Sources/StreamVideoUIKit/Info.plist b/Sources/StreamVideoUIKit/Info.plist index fa30752ad..2a735cd3a 100644 --- a/Sources/StreamVideoUIKit/Info.plist +++ b/Sources/StreamVideoUIKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.34.0 + 1.34.1 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/StreamVideo-XCFramework.podspec b/StreamVideo-XCFramework.podspec index f0ec1c477..adf9ac570 100644 --- a/StreamVideo-XCFramework.podspec +++ b/StreamVideo-XCFramework.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideo-XCFramework' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo iOS Video Client' spec.description = 'StreamVideo is the official Swift client for Stream Video, a service for building video applications.' diff --git a/StreamVideo.podspec b/StreamVideo.podspec index 37b5fd1d3..3dd692ae2 100644 --- a/StreamVideo.podspec +++ b/StreamVideo.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideo' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo iOS Video Client' spec.description = 'StreamVideo is the official Swift client for Stream Video, a service for building video applications.' diff --git a/StreamVideoArtifacts.json b/StreamVideoArtifacts.json index 595c94de5..d976a83c0 100644 --- a/StreamVideoArtifacts.json +++ b/StreamVideoArtifacts.json @@ -1 +1 @@ -{"0.4.2":"https://github.com/GetStream/stream-video-swift/releases/download/0.4.2/StreamVideo-All.zip","0.5.0":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.0/StreamVideo-All.zip","0.5.1":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.1/StreamVideo-All.zip","0.5.2":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.2/StreamVideo-All.zip","0.5.3":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.3/StreamVideo-All.zip","1.0.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.0/StreamVideo-All.zip","1.0.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.1/StreamVideo-All.zip","1.0.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.2/StreamVideo-All.zip","1.0.3":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.3/StreamVideo-All.zip","1.0.4":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.4/StreamVideo-All.zip","1.0.5":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.5/StreamVideo-All.zip","1.0.6":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.6/StreamVideo-All.zip","1.0.7":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.7/StreamVideo-All.zip","1.0.8":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.8/StreamVideo-All.zip","1.0.9":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.9/StreamVideo-All.zip","1.10.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.10.0/StreamVideo-All.zip","1.11.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.11.0/StreamVideo-All.zip","1.12.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.12.0/StreamVideo-All.zip","1.13.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.13.0/StreamVideo-All.zip","1.14.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.14.0/StreamVideo-All.zip","1.14.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.14.1/StreamVideo-All.zip","1.15.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.15.0/StreamVideo-All.zip","1.16.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.16.0/StreamVideo-All.zip","1.17.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.17.0/StreamVideo-All.zip","1.18.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.18.0/StreamVideo-All.zip","1.19.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.0/StreamVideo-All.zip","1.19.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.1/StreamVideo-All.zip","1.19.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.2/StreamVideo-All.zip","1.20.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.20.0/StreamVideo-All.zip","1.21.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.21.0/StreamVideo-All.zip","1.21.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.21.1/StreamVideo-All.zip","1.22.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.0/StreamVideo-All.zip","1.22.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.1/StreamVideo-All.zip","1.22.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.2/StreamVideo-All.zip","1.24.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.24.0/StreamVideo-All.zip","1.25.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.25.0/StreamVideo-All.zip","1.26.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.26.0/StreamVideo-All.zip","1.27.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.0/StreamVideo-All.zip","1.27.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.1/StreamVideo-All.zip","1.27.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.2/StreamVideo-All.zip","1.28.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.28.0/StreamVideo-All.zip","1.28.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.28.1/StreamVideo-All.zip","1.29.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.29.0/StreamVideo-All.zip","1.29.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.29.1/StreamVideo-All.zip","1.30.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.30.0/StreamVideo-All.zip","1.31.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.31.0/StreamVideo-All.zip","1.32.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.32.0/StreamVideo-All.zip","1.33.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.33.0/StreamVideo-All.zip","1.34.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.34.0/StreamVideo-All.zip"} \ No newline at end of file +{"0.4.2":"https://github.com/GetStream/stream-video-swift/releases/download/0.4.2/StreamVideo-All.zip","0.5.0":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.0/StreamVideo-All.zip","0.5.1":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.1/StreamVideo-All.zip","0.5.2":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.2/StreamVideo-All.zip","0.5.3":"https://github.com/GetStream/stream-video-swift/releases/download/0.5.3/StreamVideo-All.zip","1.0.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.0/StreamVideo-All.zip","1.0.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.1/StreamVideo-All.zip","1.0.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.2/StreamVideo-All.zip","1.0.3":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.3/StreamVideo-All.zip","1.0.4":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.4/StreamVideo-All.zip","1.0.5":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.5/StreamVideo-All.zip","1.0.6":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.6/StreamVideo-All.zip","1.0.7":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.7/StreamVideo-All.zip","1.0.8":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.8/StreamVideo-All.zip","1.0.9":"https://github.com/GetStream/stream-video-swift/releases/download/1.0.9/StreamVideo-All.zip","1.10.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.10.0/StreamVideo-All.zip","1.11.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.11.0/StreamVideo-All.zip","1.12.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.12.0/StreamVideo-All.zip","1.13.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.13.0/StreamVideo-All.zip","1.14.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.14.0/StreamVideo-All.zip","1.14.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.14.1/StreamVideo-All.zip","1.15.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.15.0/StreamVideo-All.zip","1.16.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.16.0/StreamVideo-All.zip","1.17.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.17.0/StreamVideo-All.zip","1.18.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.18.0/StreamVideo-All.zip","1.19.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.0/StreamVideo-All.zip","1.19.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.1/StreamVideo-All.zip","1.19.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.19.2/StreamVideo-All.zip","1.20.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.20.0/StreamVideo-All.zip","1.21.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.21.0/StreamVideo-All.zip","1.21.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.21.1/StreamVideo-All.zip","1.22.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.0/StreamVideo-All.zip","1.22.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.1/StreamVideo-All.zip","1.22.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.22.2/StreamVideo-All.zip","1.24.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.24.0/StreamVideo-All.zip","1.25.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.25.0/StreamVideo-All.zip","1.26.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.26.0/StreamVideo-All.zip","1.27.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.0/StreamVideo-All.zip","1.27.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.1/StreamVideo-All.zip","1.27.2":"https://github.com/GetStream/stream-video-swift/releases/download/1.27.2/StreamVideo-All.zip","1.28.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.28.0/StreamVideo-All.zip","1.28.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.28.1/StreamVideo-All.zip","1.29.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.29.0/StreamVideo-All.zip","1.29.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.29.1/StreamVideo-All.zip","1.30.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.30.0/StreamVideo-All.zip","1.31.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.31.0/StreamVideo-All.zip","1.32.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.32.0/StreamVideo-All.zip","1.33.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.33.0/StreamVideo-All.zip","1.34.0":"https://github.com/GetStream/stream-video-swift/releases/download/1.34.0/StreamVideo-All.zip","1.34.1":"https://github.com/GetStream/stream-video-swift/releases/download/1.34.1/StreamVideo-All.zip"} \ No newline at end of file diff --git a/StreamVideoSwiftUI-XCFramework.podspec b/StreamVideoSwiftUI-XCFramework.podspec index b9b5ccd1f..c542308da 100644 --- a/StreamVideoSwiftUI-XCFramework.podspec +++ b/StreamVideoSwiftUI-XCFramework.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideoSwiftUI-XCFramework' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo SwiftUI Video Components' spec.description = 'StreamVideoSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamVideo SDK.' diff --git a/StreamVideoSwiftUI.podspec b/StreamVideoSwiftUI.podspec index 2d6cd3dbf..835ad3106 100644 --- a/StreamVideoSwiftUI.podspec +++ b/StreamVideoSwiftUI.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideoSwiftUI' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo SwiftUI Video Components' spec.description = 'StreamVideoSwiftUI SDK offers flexible SwiftUI components able to display data provided by StreamVideo SDK.' diff --git a/StreamVideoTests/Utils/AudioSession/AudioRecorder/Namespace/Middleware/StreamCallAudioRecorder_CategoryMiddlewareTests.swift b/StreamVideoTests/Utils/AudioSession/AudioRecorder/Namespace/Middleware/StreamCallAudioRecorder_CategoryMiddlewareTests.swift index 9a86bea19..e8e962941 100644 --- a/StreamVideoTests/Utils/AudioSession/AudioRecorder/Namespace/Middleware/StreamCallAudioRecorder_CategoryMiddlewareTests.swift +++ b/StreamVideoTests/Utils/AudioSession/AudioRecorder/Namespace/Middleware/StreamCallAudioRecorder_CategoryMiddlewareTests.swift @@ -26,7 +26,7 @@ final class StreamCallAudioRecorder_CategoryMiddlewareTests: XCTestCase, @unchec validation.isInverted = true subject.dispatcher = .init { _, _, _, _ in } - audioStore.dispatch(.audioSession(.setCategory(.playAndRecord, mode: .videoChat, options: []))) + audioStore.dispatch(.audioSession(.setCategory(.playAndRecord, mode: .voiceChat, options: []))) await safeFulfillment(of: [validation], timeout: 1) } @@ -36,7 +36,7 @@ final class StreamCallAudioRecorder_CategoryMiddlewareTests: XCTestCase, @unchec validation.isInverted = true subject.dispatcher = .init { _, _, _, _ in } - audioStore.dispatch(.audioSession(.setCategory(.record, mode: .videoChat, options: []))) + audioStore.dispatch(.audioSession(.setCategory(.record, mode: .voiceChat, options: []))) await safeFulfillment(of: [validation], timeout: 1) } @@ -52,7 +52,7 @@ final class StreamCallAudioRecorder_CategoryMiddlewareTests: XCTestCase, @unchec } } - audioStore.dispatch(.audioSession(.setCategory(.playback, mode: .videoChat, options: []))) + audioStore.dispatch(.audioSession(.setCategory(.playback, mode: .voiceChat, options: []))) await safeFulfillment(of: [validation]) } diff --git a/StreamVideoTests/Utils/AudioSession/Extensions/AVAudioSessionCategoryOptions_Tests.swift b/StreamVideoTests/Utils/AudioSession/Extensions/AVAudioSessionCategoryOptions_Tests.swift index 29efa78f5..fb2a54cfa 100644 --- a/StreamVideoTests/Utils/AudioSession/Extensions/AVAudioSessionCategoryOptions_Tests.swift +++ b/StreamVideoTests/Utils/AudioSession/Extensions/AVAudioSessionCategoryOptions_Tests.swift @@ -18,7 +18,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: false ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -31,7 +32,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: false ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -44,7 +46,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: false ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -57,7 +60,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: true ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -71,7 +75,7 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable ), [ .allowBluetooth, - .defaultToSpeaker + .allowBluetoothA2DP ] ) } @@ -84,7 +88,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: true ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -97,7 +102,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: true ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -110,7 +116,8 @@ final class AVAudioSessionCategoryOptionsTests: XCTestCase, @unchecked Sendable appIsInForeground: false ), [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } diff --git a/StreamVideoTests/Utils/AudioSession/Policies/DefaultAudioSessionPolicyTests.swift b/StreamVideoTests/Utils/AudioSession/Policies/DefaultAudioSessionPolicyTests.swift index 42d0e2148..d7370fc9c 100644 --- a/StreamVideoTests/Utils/AudioSession/Policies/DefaultAudioSessionPolicyTests.swift +++ b/StreamVideoTests/Utils/AudioSession/Policies/DefaultAudioSessionPolicyTests.swift @@ -35,11 +35,12 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { ) XCTAssertEqual(configuration.category, .playAndRecord) - XCTAssertEqual(configuration.mode, .videoChat) + XCTAssertEqual(configuration.mode, .voiceChat) XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, .speaker) @@ -56,11 +57,12 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { ) XCTAssertEqual(configuration.category, .playAndRecord) - XCTAssertEqual(configuration.mode, .videoChat) + XCTAssertEqual(configuration.mode, .voiceChat) XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertNotNil(configuration.overrideOutputAudioPort) @@ -80,7 +82,8 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, AVAudioSession.PortOverride.none) @@ -97,11 +100,12 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { ) XCTAssertEqual(configuration.category, .playAndRecord) - XCTAssertEqual(configuration.mode, .videoChat) + XCTAssertEqual(configuration.mode, .voiceChat) XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertNotNil(configuration.overrideOutputAudioPort) @@ -124,7 +128,7 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { configuration.options, [ .allowBluetooth, - .defaultToSpeaker + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, .speaker) @@ -145,7 +149,8 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertNotNil(configuration.overrideOutputAudioPort) @@ -166,7 +171,8 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, AVAudioSession.PortOverride.none) @@ -187,7 +193,8 @@ final class DefaultAudioSessionPolicyTests: XCTestCase, @unchecked Sendable { XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertNotNil(configuration.overrideOutputAudioPort) diff --git a/StreamVideoTests/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicyTests.swift b/StreamVideoTests/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicyTests.swift index 9b2046bdb..941896157 100644 --- a/StreamVideoTests/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicyTests.swift +++ b/StreamVideoTests/Utils/AudioSession/Policies/OwnCapabilitiesAudioSessionPolicyTests.swift @@ -71,7 +71,8 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, AVAudioSession.PortOverride.none) @@ -92,11 +93,12 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda // Then XCTAssertEqual(configuration.category, .playAndRecord) - XCTAssertEqual(configuration.mode, .videoChat) + XCTAssertEqual(configuration.mode, .voiceChat) XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) XCTAssertEqual(configuration.overrideOutputAudioPort, .speaker) @@ -144,23 +146,6 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda // MARK: - Tests for different video settings - func testConfiguration_WhenVideoOnSpeakerOn_ReturnsVideoChatMode() async { - // Given - currentDeviceType = .phone - await fulfilmentInMainActor { self.currentDevice.deviceType == self.currentDeviceType } - let callSettings = CallSettings(audioOn: true, videoOn: true, speakerOn: true) - let ownCapabilities: Set = [.sendAudio, .sendVideo] - - // When - let configuration = subject.configuration( - for: callSettings, - ownCapabilities: ownCapabilities - ) - - // Then - XCTAssertEqual(configuration.mode, .videoChat) - } - func testConfiguration_WhenVideoOffSpeakerOnBackgroundFalse_ReturnsVoiceChatMode() async { // Given currentDeviceType = .phone @@ -180,7 +165,7 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda configuration.options, [ .allowBluetooth, - .defaultToSpeaker + .allowBluetoothA2DP ] ) } @@ -203,7 +188,8 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -227,7 +213,8 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } @@ -251,7 +238,8 @@ final class OwnCapabilitiesAudioSessionPolicyTests: XCTestCase, @unchecked Senda XCTAssertEqual( configuration.options, [ - .allowBluetooth + .allowBluetooth, + .allowBluetoothA2DP ] ) } diff --git a/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Effects/RouteChangeEffect_Tests.swift b/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Effects/RouteChangeEffect_Tests.swift index 35dd83adb..ac1a02630 100644 --- a/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Effects/RouteChangeEffect_Tests.swift +++ b/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Effects/RouteChangeEffect_Tests.swift @@ -109,6 +109,8 @@ final class RouteChangeEffect_Tests: XCTestCase, @unchecked Sendable { CurrentDevice.currentValue = .init { currentDevice } await fulfillment { CurrentDevice.currentValue.deviceType == currentDevice } _ = subject + // we send this one to be the one that will be dropped + callSettingsSubject.send(activeCallSettings.withUpdatedAudioOutputState(false)) callSettingsSubject.send(activeCallSettings) store.session.category = category.rawValue store.session.currentRoute = updatedRoute diff --git a/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Reducers/RTCAudioSessionReducer_Tests.swift b/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Reducers/RTCAudioSessionReducer_Tests.swift index 3959bbaf9..6b5063d62 100644 --- a/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Reducers/RTCAudioSessionReducer_Tests.swift +++ b/StreamVideoTests/Utils/AudioSession/RTCAudioStore/Reducers/RTCAudioSessionReducer_Tests.swift @@ -140,7 +140,7 @@ final class RTCAudioSessionReducer_Tests: XCTestCase, @unchecked Sendable { action: .audioSession( .setCategory( .playAndRecord, - mode: .videoChat, + mode: .voiceChat, options: [ .allowBluetooth, .mixWithOthers @@ -160,7 +160,7 @@ final class RTCAudioSessionReducer_Tests: XCTestCase, @unchecked Sendable { )?.first ) XCTAssertEqual(input.category, AVAudioSession.Category.playAndRecord.rawValue) - XCTAssertEqual(input.mode, AVAudioSession.Mode.videoChat.rawValue) + XCTAssertEqual(input.mode, AVAudioSession.Mode.voiceChat.rawValue) XCTAssertEqual(input.categoryOptions, [.allowBluetooth, .mixWithOthers]) } @@ -175,7 +175,7 @@ final class RTCAudioSessionReducer_Tests: XCTestCase, @unchecked Sendable { action: .audioSession( .setCategory( .playAndRecord, - mode: .videoChat, + mode: .voiceChat, options: [ .allowBluetooth, .mixWithOthers @@ -188,7 +188,7 @@ final class RTCAudioSessionReducer_Tests: XCTestCase, @unchecked Sendable { ) XCTAssertEqual(updatedState.category, .playAndRecord) - XCTAssertEqual(updatedState.mode, .videoChat) + XCTAssertEqual(updatedState.mode, .voiceChat) XCTAssertEqual(updatedState.options, [.allowBluetooth, .mixWithOthers]) } diff --git a/StreamVideoUIKit-XCFramework.podspec b/StreamVideoUIKit-XCFramework.podspec index 8d1226541..645c643de 100644 --- a/StreamVideoUIKit-XCFramework.podspec +++ b/StreamVideoUIKit-XCFramework.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideoUIKit-XCFramework' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo UIKit Video Components' spec.description = 'StreamVideoUIKit SDK offers flexible UIKit components able to display data provided by StreamVideo SDK.' @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| spec.framework = 'Foundation', 'UIKit' spec.module_name = 'StreamVideoUIKit' - spec.source = { http: "https://github.com/GetStream/stream-video-swift/releases/download//#{spec.version}/#{spec.module_name}.zip" } + spec.source = { http: "https://github.com/GetStream/stream-video-swift/releases/download/#{spec.version}/#{spec.module_name}.zip" } spec.vendored_frameworks = "#{spec.module_name}.xcframework" spec.preserve_paths = "#{spec.module_name}.xcframework/*" diff --git a/StreamVideoUIKit.podspec b/StreamVideoUIKit.podspec index a514d04a7..1b3f1a304 100644 --- a/StreamVideoUIKit.podspec +++ b/StreamVideoUIKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'StreamVideoUIKit' - spec.version = '1.34.0' + spec.version = '1.34.1' spec.summary = 'StreamVideo UIKit Video Components' spec.description = 'StreamVideoUIKit SDK offers flexible UIKit components able to display data provided by StreamVideo SDK.' diff --git a/SwiftUIDemoAppUITests/Pages/CallDetailsPage.swift b/SwiftUIDemoAppUITests/Pages/CallDetailsPage.swift index 96070c8a5..f5461443c 100644 --- a/SwiftUIDemoAppUITests/Pages/CallDetailsPage.swift +++ b/SwiftUIDemoAppUITests/Pages/CallDetailsPage.swift @@ -24,6 +24,7 @@ enum CallDetailsPage { return app.collectionViews["participantList"] } } + static var participants: XCUIElementQuery { participantList.buttons } static var connectionErrorAlert: XCUIElement { app.staticTexts.matching(NSPredicate(format: "label CONTAINS 'failed with error'")).firstMatch diff --git a/SwiftUIDemoAppUITests/Pages/CallPage.swift b/SwiftUIDemoAppUITests/Pages/CallPage.swift index a350e4037..a7a113ce7 100644 --- a/SwiftUIDemoAppUITests/Pages/CallPage.swift +++ b/SwiftUIDemoAppUITests/Pages/CallPage.swift @@ -45,6 +45,7 @@ enum CallPage { static var participantsBubblesWithImages: XCUIElementQuery { app.staticTexts["callConnectingGroupView"].images } + static var participantsBubblesWithoutImages: XCUIElementQuery { app.staticTexts["callConnectingGroupView"].staticTexts } @@ -73,13 +74,16 @@ enum CallPage { static var screenSharingParticipantView: XCUIElementQuery { spotlightParticipantView } + static var screenSharingParticipantList: XCUIElement { spotlightViewParticipantList } + static var gridViewParticipantList: XCUIElement { app.scrollViews["gridScrollView"] } static var gridViewParticipantListDetails: XCUIElement { gridViewParticipantList.otherElements.matching(NSPredicate(format: "label CONTAINS 'Vertical scroll bar'")).firstMatch } + static var spotlightViewParticipantList: XCUIElement { app.scrollViews["horizontalParticipantsList"] } static var reconnectingMessage: XCUIElement { app.staticTexts["reconnectingMessage"] } } diff --git a/SwiftUIDemoAppUITests/Pages/LoginPage.swift b/SwiftUIDemoAppUITests/Pages/LoginPage.swift index 6fc88bf57..3e49b9e50 100644 --- a/SwiftUIDemoAppUITests/Pages/LoginPage.swift +++ b/SwiftUIDemoAppUITests/Pages/LoginPage.swift @@ -7,5 +7,4 @@ import XCTest enum LoginPage { static var users: XCUIElementQuery { app.buttons.matching(NSPredicate(format: "identifier LIKE 'userName'")) } - } diff --git a/SwiftUIDemoAppUITests/Robots/UserRobot+Asserts.swift b/SwiftUIDemoAppUITests/Robots/UserRobot+Asserts.swift index 6995ba07a..fd49fdf0e 100644 --- a/SwiftUIDemoAppUITests/Robots/UserRobot+Asserts.swift +++ b/SwiftUIDemoAppUITests/Robots/UserRobot+Asserts.swift @@ -20,7 +20,11 @@ extension UserRobot { @discardableResult private func assertParticipantEvent(_ expectedText: String) -> Self { - let participantEvent = CallPage.participantEvent.wait().waitForText(expectedText, timeout: UserRobot.defaultTimeout, mustBeEqual: false) + let participantEvent = CallPage.participantEvent.wait().waitForText( + expectedText, + timeout: UserRobot.defaultTimeout, + mustBeEqual: false + ) let errMessage = "`\(participantEvent.label)` does not contain `\(expectedText)`" XCTAssertTrue(participantEvent.label.contains(expectedText), errMessage) return self @@ -60,11 +64,15 @@ extension UserRobot { private func assertToogle(_ toogle: XCUIElement, state: UserControls) -> Self { switch state { case .enable: - XCTAssertTrue(toogle.wait().waitForValue("1", timeout: UserRobot.defaultTimeout).isOn, - "Toggle should be on") + XCTAssertTrue( + toogle.wait().waitForValue("1", timeout: UserRobot.defaultTimeout).isOn, + "Toggle should be on" + ) case .disable: - XCTAssertTrue(toogle.wait().waitForValue("0", timeout: UserRobot.defaultTimeout).isOff, - "Toggle should be off") + XCTAssertTrue( + toogle.wait().waitForValue("0", timeout: UserRobot.defaultTimeout).isOff, + "Toggle should be off" + ) } return self } @@ -79,7 +87,10 @@ extension UserRobot { func assertParticipantStartSharingScreen() -> Self { let expectedText = "presenting" XCTAssertTrue(CallPage.screenSharingView.wait(timeout: UserRobot.defaultTimeout).exists, "screenSharingView should appear") - XCTAssertTrue(CallPage.screenSharingLabel.label.contains(expectedText), "`\(CallPage.screenSharingLabel.label)` does not contain `\(expectedText)`") + XCTAssertTrue( + CallPage.screenSharingLabel.label.contains(expectedText), + "`\(CallPage.screenSharingLabel.label)` does not contain `\(expectedText)`" + ) return self } @@ -88,7 +99,10 @@ extension UserRobot { if isVisible { XCTAssertTrue(CallPage.recordingView.wait().exists, "recording icon should appear") } else { - XCTAssertFalse(CallPage.recordingView.waitForDisappearance(timeout: UserRobot.defaultTimeout).exists, "recording icon should disappear") + XCTAssertFalse( + CallPage.recordingView.waitForDisappearance(timeout: UserRobot.defaultTimeout).exists, + "recording icon should disappear" + ) } return self } @@ -98,14 +112,21 @@ extension UserRobot { if isVisible { XCTAssertTrue(CallPage.callDurationView.wait().exists, "callDurationView should appear") } else { - XCTAssertFalse(CallPage.callDurationView.waitForDisappearance(timeout: UserRobot.defaultTimeout).exists, "callDurationView should disappear") + XCTAssertFalse( + CallPage.callDurationView.waitForDisappearance(timeout: UserRobot.defaultTimeout).exists, + "callDurationView should disappear" + ) } return self } @discardableResult func assertUserCountWhenScreenSharing(_ userCount: Int) -> Self { - let actualViewsCount = CallPage.screenSharingParticipantView.waitCount(userCount, timeout: UserRobot.defaultTimeout, exact: true).count + let actualViewsCount = CallPage.screenSharingParticipantView.waitCount( + userCount, + timeout: UserRobot.defaultTimeout, + exact: true + ).count XCTAssertEqual(userCount, actualViewsCount) return self } @@ -118,14 +139,18 @@ extension UserRobot { @discardableResult private func assertParticipantListVisibility(expectedPercent: Int, details: XCUIElement) -> Self { let expectedValue = "\(expectedPercent)%" - let actualValue = (details.wait().waitForValue("\(expectedPercent)", mustBeEqual: false).value as! String).filter { !$0.isWhitespace } + let actualValue = (details.wait().waitForValue("\(expectedPercent)", mustBeEqual: false).value as! String) + .filter { !$0.isWhitespace } XCTAssertEqual(expectedValue, actualValue) return self } @discardableResult func assertParticipantStopSharingScreen() -> Self { - XCTAssertFalse(CallPage.screenSharingView.waitForDisappearance(timeout: Self.defaultTimeout).exists, "screenSharingView should disappear") + XCTAssertFalse( + CallPage.screenSharingView.waitForDisappearance(timeout: Self.defaultTimeout).exists, + "screenSharingView should disappear" + ) XCTAssertFalse(CallPage.screenSharingLabel.exists, "screenSharingLabel should disappear") XCTAssertEqual(0, CallPage.screenSharingParticipantView.count) return self @@ -162,15 +187,26 @@ extension UserRobot { XCTAssertTrue(CallPage.ConnectingView.callConnectingView.wait().exists, "callConnectingView should appear") XCTAssertTrue(CallPage.ConnectingView.callingIndicator.exists, "callingIndicator should appear") if participantCount > 3 { - XCTAssertEqual(3, CallPage.ConnectingView.participantsBubblesWithImages.count + CallPage.ConnectingView.participantsBubblesWithoutImages.count) + XCTAssertEqual( + 3, + CallPage.ConnectingView.participantsBubblesWithImages.count + CallPage.ConnectingView + .participantsBubblesWithoutImages.count + ) XCTAssertEqual("+\(participantCount - 2)", CallPage.ConnectingView.participantsBubblesWithoutImages.lastMatch?.text) } else if participantCount > 1 { - XCTAssertEqual(participantCount, CallPage.ConnectingView.participantsBubblesWithImages.count + CallPage.ConnectingView.participantsBubblesWithoutImages.count) + XCTAssertEqual( + participantCount, + CallPage.ConnectingView.participantsBubblesWithImages.count + CallPage.ConnectingView + .participantsBubblesWithoutImages.count + ) if let name = CallPage.ConnectingView.participantsBubblesWithoutImages.lastMatch?.text { XCTAssertFalse(name.contains("+")) } } else if participantCount > 0 { - XCTAssertTrue(CallPage.ConnectingView.callConnectingParticipantView.exists, "callConnectingParticipantView should appear") + XCTAssertTrue( + CallPage.ConnectingView.callConnectingParticipantView.exists, + "callConnectingParticipantView should appear" + ) } return self } @@ -198,7 +234,10 @@ extension UserRobot { let maxVisibleCount = 6 let actualCount = CallPage.spotlightParticipantView.count if participantCount > maxVisibleCount { - XCTAssertTrue(actualCount >= maxVisibleCount && actualCount <= participantCount, "SpotlightView, expected: \(maxVisibleCount) <= \(actualCount) <= \(participantCount)") + XCTAssertTrue( + actualCount >= maxVisibleCount && actualCount <= participantCount, + "SpotlightView, expected: \(maxVisibleCount) <= \(actualCount) <= \(participantCount)" + ) } else { XCTAssertEqual(participantCount, actualCount, "SpotlightView") } @@ -241,7 +280,10 @@ extension UserRobot { if isVisible { XCTAssertTrue(CallPage.reconnectingMessage.wait().exists, "reconnectingMessage should appear") } else { - XCTAssertFalse(CallPage.reconnectingMessage.waitForDisappearance(timeout: UserRobot.defaultTimeout * 2).exists, "reconnectingMessage should disappear") + XCTAssertFalse( + CallPage.reconnectingMessage.waitForDisappearance(timeout: UserRobot.defaultTimeout * 2).exists, + "reconnectingMessage should disappear" + ) } return self } diff --git a/SwiftUIDemoAppUITests/StreamVideoUITests.swift b/SwiftUIDemoAppUITests/StreamVideoUITests.swift index 15be132f7..d7c85c208 100644 --- a/SwiftUIDemoAppUITests/StreamVideoUITests.swift +++ b/SwiftUIDemoAppUITests/StreamVideoUITests.swift @@ -2,7 +2,7 @@ // Copyright © 2025 Stream.io Inc. All rights reserved. // -@_exported import StreamSwiftTestHelpers import Foundation +@_exported import StreamSwiftTestHelpers final class StreamVideoUITests {} diff --git a/SwiftUIDemoAppUITests/Tests/Authentication_Tests.swift b/SwiftUIDemoAppUITests/Tests/Authentication_Tests.swift index fd9f4f367..96a72a87a 100644 --- a/SwiftUIDemoAppUITests/Tests/Authentication_Tests.swift +++ b/SwiftUIDemoAppUITests/Tests/Authentication_Tests.swift @@ -121,7 +121,7 @@ final class Authentication_Tests: StreamTestCase { userRobot .waitForAutoLogin() .startCall(callId, waitForCompletion: false) - } + } WHEN("app requests a token refresh") {} THEN("app shows a connection error alert") { userRobot.assertConnectionErrorAlert() diff --git a/SwiftUIDemoAppUITests/Tests/CallViewsTests.swift b/SwiftUIDemoAppUITests/Tests/CallViewsTests.swift index 98a01d032..d985d2f28 100644 --- a/SwiftUIDemoAppUITests/Tests/CallViewsTests.swift +++ b/SwiftUIDemoAppUITests/Tests/CallViewsTests.swift @@ -2,8 +2,8 @@ // Copyright © 2025 Stream.io Inc. All rights reserved. // -import XCTest import StreamVideo +import XCTest final class CallViewsTests: StreamTestCase { @@ -147,7 +147,9 @@ final class CallViewsTests: StreamTestCase { THEN("there are \(participants) participants on the call") { userRobot .assertCallControls() - .assertSpotlightView(with: participants - 1) // We get one less due to the LazyHStack that initializes only a few items after the visible ones + .assertSpotlightView(with: participants - + 1 + ) // We get one less due to the LazyHStack that initializes only a few items after the visible ones } WHEN("user enables fullscreen view") { userRobot.setView(mode: .fullscreen) diff --git a/SwiftUIDemoAppUITests/Tests/DeeplinkTests.swift b/SwiftUIDemoAppUITests/Tests/DeeplinkTests.swift index 48d7cdde8..1f2313134 100644 --- a/SwiftUIDemoAppUITests/Tests/DeeplinkTests.swift +++ b/SwiftUIDemoAppUITests/Tests/DeeplinkTests.swift @@ -7,7 +7,7 @@ import XCTest // Requires running a standalone Sinatra server final class DeeplinkTests: StreamTestCase { - static override func setUp() { + override static func setUp() { super.setUp() // We are launching and terminating the app to ensure the executable @@ -52,7 +52,7 @@ final class DeeplinkTests: StreamTestCase { try [ "https://getstream.io/.well-known/apple-app-site-association", "https://staging.getstream.io/.well-known/apple-app-site-association", - "https://pronto.getstream.io/.well-known/apple-app-site-association", + "https://pronto.getstream.io/.well-known/apple-app-site-association" ].forEach { try assertEnvironment($0) } } diff --git a/TestTools/Robots/ParticipantRobot.swift b/TestTools/Robots/ParticipantRobot.swift index 7193d5cc2..a01a514ad 100644 --- a/TestTools/Robots/ParticipantRobot.swift +++ b/TestTools/Robots/ParticipantRobot.swift @@ -6,9 +6,9 @@ import XCTest public class ParticipantRobot { private let videoBuddyUrlString = "http://localhost:5678/stream-video-buddy" - private var screenSharingDuration: Int? = nil - private var callRecordingDuration: Int? = nil - private var messageCount: Int? = nil + private var screenSharingDuration: Int? + private var callRecordingDuration: Int? + private var messageCount: Int? private var userCount: Int = 1 private var callDuration: Double = TestRunnerEnvironment.isCI ? 60 : 30 private var _showWindow: Bool = false diff --git a/TestTools/TestData/ImageFactory.swift b/TestTools/TestData/ImageFactory.swift index 4c32cc696..e1c3e1def 100644 --- a/TestTools/TestData/ImageFactory.swift +++ b/TestTools/TestData/ImageFactory.swift @@ -4,7 +4,7 @@ import Foundation -struct ImageFactory { +enum ImageFactory { static func get(_ number: Int) -> URL? { switch number { diff --git a/TestTools/TestData/ViewFactory.swift b/TestTools/TestData/ViewFactory.swift index b35eeb10c..7b8018233 100644 --- a/TestTools/TestData/ViewFactory.swift +++ b/TestTools/TestData/ViewFactory.swift @@ -2,9 +2,9 @@ // Copyright © 2025 Stream.io Inc. All rights reserved. // -import SwiftUI @testable import StreamVideo @testable import StreamVideoSwiftUI +import SwiftUI class TestViewFactory: ViewFactory { @@ -55,7 +55,7 @@ class TestViewFactory: ViewFactory { } } -struct ParticipantFactory { +enum ParticipantFactory { static func get( _ count: Int, withVideo hasVideo: Bool = false, @@ -95,7 +95,7 @@ struct ParticipantFactory { } } -struct UserFactory { +enum UserFactory { static func get(_ count: Int) -> [Member] { var factory: [Member] = [] guard count > 0 else { return factory } diff --git a/TestTools/UITests/Safari.swift b/TestTools/UITests/Safari.swift index 9465c5ce0..b4754099f 100644 --- a/TestTools/UITests/Safari.swift +++ b/TestTools/UITests/Safari.swift @@ -42,6 +42,7 @@ struct Safari { return self } + // swiftformat:disable isEmpty @discardableResult func alertHandler() -> Self { safari.buttons["ReloadButton"].wait() @@ -53,6 +54,8 @@ struct Safari { } return self } + + // swiftformat:enable isEmpty @discardableResult func tapOnDeeplinkButton(_ timeout: Double = 5) -> Self { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 5084a3940..2a9c99078 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -671,13 +671,9 @@ desc 'Run source code formatting/linting' lane :run_swift_format do |options| Dir.chdir('..') do strict = options[:strict] ? '--lint' : nil - sources_matrix[:swiftformat].each do |path| - sh("swiftformat #{strict} --config .swiftformat #{path}") - next if path.include?('Tests') - - sh("swiftlint lint --config .swiftlint.yml --fix --progress --quiet --reporter json #{path}") unless strict - sh("swiftlint lint --config .swiftlint.yml --strict --progress --quiet --reporter json #{path}") - end + sh("swiftformat #{strict} --config .swiftformat .") + sh("swiftlint lint --config .swiftlint.yml --fix --progress --quiet --reporter json") unless strict + sh("swiftlint lint --config .swiftlint.yml --strict --progress --quiet --reporter json") end end @@ -708,8 +704,7 @@ lane :sources_matrix do documentation_tests: ['Sources', 'DocumentationTests', xcode_project], size: ['Sources', xcode_project], public_interface: ['Sources'], - ruby: ['fastlane'], - swiftformat: ['Sources', 'DemoApp', 'DemoAppUIKit', 'StreamVideoTests', 'StreamVideoSwiftUITests', 'StreamVideoUIKitTests'] + ruby: ['fastlane'] } end diff --git a/lefthook.yml b/lefthook.yml index 4efabfb84..61221d999 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -4,11 +4,6 @@ pre-commit: - run: swiftlint lint --config .swiftlint.yml --fix --progress --reporter json {staged_files} glob: "*.{swift}" stage_fixed: true - exclude: - - "**/Generated/**" - - "**/generated/**" - - "**/protobuf/**" - - "**/OpenApi/**" skip: - merge - rebase @@ -16,11 +11,6 @@ pre-commit: - run: swiftformat --config .swiftformat {staged_files} glob: "*.{swift}" stage_fixed: true - exclude: - - "**/Generated/**" - - "**/generated/**" - - "**/protobuf/**" - - "**/OpenApi/**" skip: - merge - rebase @@ -29,10 +19,5 @@ pre-push: jobs: - run: swiftlint lint --config .swiftlint.yml --strict --progress --reporter json {push_files} glob: "*.{swift}" - exclude: - - "**/Generated/**" - - "**/generated/**" - - "**/protobuf/**" - - "**/OpenApi/**" skip: - merge-commit