diff --git a/CHANGELOG.md b/CHANGELOG.md index 251d58be2..69a0594b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### ✅ Added - When the user is missing a permission, the SDK will prompt them to accept any missing permission. [#915](https://github.com/GetStream/stream-video-swift/pull/915) +- You can now set the `ViewFactory` instance to be used from Picture-in-Picture. [#934](https://github.com/GetStream/stream-video-swift/pull/934) - `CallParticipant` now exposes the `source` property, which can be used to distinguish between WebRTC users and ingest sources like RTMP or SIP. [#93](https://github.com/GetStream/stream-video-swift/pull/933) ### 🔄 Changed diff --git a/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/PictureInPictureViewFactory.swift b/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/PictureInPictureViewFactory.swift index 9f855b7c6..49a6ee6b0 100644 --- a/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/PictureInPictureViewFactory.swift +++ b/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/PictureInPictureViewFactory.swift @@ -14,6 +14,8 @@ import SwiftUI /// ensures thread safety with `@unchecked Sendable` conformance. final class PictureInPictureViewFactory: @unchecked Sendable { + let source: any ViewFactory + private let _makeParticipantImageView: (CallParticipant) -> AnyView /// Creates a new instance of `PictureInPictureViewFactory`. @@ -22,6 +24,7 @@ final class PictureInPictureViewFactory: @unchecked Sendable { /// protocol, used to create the participant image views. @MainActor init(_ viewFactory: Factory) { + source = viewFactory _makeParticipantImageView = { AnyView( CallParticipantImageView( diff --git a/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/StreamPictureInPictureAdapter.swift b/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/StreamPictureInPictureAdapter.swift index 0d4dc2e4f..57011030a 100644 --- a/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/StreamPictureInPictureAdapter.swift +++ b/Sources/StreamVideoSwiftUI/Utils/PictureInPicture/StreamPictureInPictureAdapter.swift @@ -82,6 +82,17 @@ public final class StreamPictureInPictureAdapter: @unchecked Sendable { .store(in: disposableBag) } } + + // MARK: - State updaters + + /// Updates the ViewFactory instance the will be used by Picture-in-Picture to create UI components. + @MainActor + public func setViewFactory(_ viewFactory: V) { + guard let store else { + return + } + store.dispatch(.setViewFactory(.init(viewFactory))) + } } /// Provides the default value for the Picture-in-Picture adapter. diff --git a/StreamVideoSwiftUITests/Utils/PictureInPicture/StreamPictureInPictureAdapterTests.swift b/StreamVideoSwiftUITests/Utils/PictureInPicture/StreamPictureInPictureAdapterTests.swift index 7c924fc7e..13ff49f7c 100644 --- a/StreamVideoSwiftUITests/Utils/PictureInPicture/StreamPictureInPictureAdapterTests.swift +++ b/StreamVideoSwiftUITests/Utils/PictureInPicture/StreamPictureInPictureAdapterTests.swift @@ -37,4 +37,18 @@ final class StreamPictureInPictureAdapterTests: XCTestCase, @unchecked Sendable await fulfilmentInMainActor { self.subject.store?.state.sourceView === view } } + + // MARK: - ViewFactory updated + + @MainActor + func test_setViewFactory_storeWasUpdated() async { + final class CustomViewFactory: ViewFactory {} + _ = subject + await fulfillment { self.subject.store != nil } + let viewFactory = CustomViewFactory() + + subject.setViewFactory(viewFactory) + + await fulfillment { self.subject.store?.state.viewFactory.source === viewFactory } + } }