Use native video call picture in picture! (#3190)

* Use native video call picture in picture!

* Handle isSupported, isPossible and web view errors.

* Use new canEnterPip method.

* Hide a room's Call button when already joined to the call.

* Tweak feature flag description.

* PR comments.
This commit is contained in:
Doug
2024-08-21 17:48:57 +01:00
committed by GitHub
parent 4e3ab9c04a
commit 304070e8cc
23 changed files with 256 additions and 66 deletions
@@ -73,8 +73,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
switch action {
case let .setAudioEnabled(enabled, roomID):
guard roomID == configuration.callID else {
MXLog.error("Received mute request for a different room: \(roomID) != \(configuration.callID)")
guard roomID == configuration.callRoomID else {
MXLog.error("Received mute request for a different room: \(roomID) != \(configuration.callRoomID)")
return
}
@@ -107,28 +107,11 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
case .callEnded:
actionsSubject.send(.dismiss)
case .mediaStateChanged(let audioEnabled, _):
elementCallService.setAudioEnabled(audioEnabled, roomID: configuration.callID)
elementCallService.setAudioEnabled(audioEnabled, roomID: configuration.callRoomID)
}
}
.store(in: &cancellables)
// Use did start otherwise there's a black box left on the screen during the pip controller animation.
NotificationCenter.default.publisher(for: .init("AVPictureInPictureControllerDidStartNotification"))
.sink { [weak self] notification in
guard let self else { return }
let controller = notification.object as? AVPictureInPictureController
actionsSubject.send(.pictureInPictureStarted(controller))
}
.store(in: &cancellables)
NotificationCenter.default.publisher(for: .init("AVPictureInPictureControllerWillStopNotification"))
.sink { [weak self] _ in
guard let self else { return }
actionsSubject.send(.pictureInPictureStopped)
Task { try await self.state.bindings.javaScriptEvaluator?("controls.disableCompatPip()") }
}
.store(in: &cancellables)
setupCall()
}
@@ -138,7 +121,11 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
guard let url else { return }
MXLog.info("URL changed to: \(url)")
case .navigateBack:
handleBackwardsNavigation()
Task { await handleBackwardsNavigation() }
case .pictureInPictureWillStop:
actionsSubject.send(.pictureInPictureStopped)
case .endCall:
actionsSubject.send(.dismiss)
}
}
@@ -200,26 +187,19 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
}
}
private func handleBackwardsNavigation() {
#if targetEnvironment(simulator)
if UIDevice.current.isPhone {
MXLog.warning("The iPhone simulator doesn't support PiP.")
actionsSubject.send(.dismiss)
return
}
#endif
guard isPictureInPictureEnabled, state.url != nil else {
private func handleBackwardsNavigation() async {
guard state.url != nil,
isPictureInPictureEnabled,
let requestPictureInPictureHandler = state.bindings.requestPictureInPictureHandler else {
actionsSubject.send(.dismiss)
return
}
Task {
try await state.bindings.javaScriptEvaluator?("controls.enableCompatPip()")
// Enable this check when implemented on web.
// if result as? Bool != true {
// actionsSubject.send(.dismiss)
// }
switch await requestPictureInPictureHandler() {
case .success(let controller):
actionsSubject.send(.pictureInPictureStarted(controller))
case .failure:
actionsSubject.send(.dismiss)
}
}