Skip to content

Commit

Permalink
Handle isSupported, isPossible and web view errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
pixlwave committed Aug 21, 2024
1 parent 49cc8df commit eb0a84e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 25 deletions.
8 changes: 7 additions & 1 deletion ElementX/Sources/Screens/CallScreen/CallScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct CallScreenViewState: BindableState {
struct Bindings {
var javaScriptMessageHandler: ((Any) -> Void)?
var javaScriptEvaluator: ((String) async throws -> Any)?
var requestPictureInPictureHandler: (() -> AVPictureInPictureController)?
var requestPictureInPictureHandler: (() async -> Result<AVPictureInPictureController, CallScreenError>)?

var alertInfo: AlertInfo<UUID>?
}
Expand All @@ -45,4 +45,10 @@ enum CallScreenViewAction {
case urlChanged(URL?)
case navigateBack
case pictureInPictureWillStop
case endCall
}

enum CallScreenError: Error {
case webViewError(Error)
case pictureInPictureNotSupported
}
23 changes: 10 additions & 13 deletions ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +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)
}
}

Expand Down Expand Up @@ -185,25 +187,20 @@ 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

private func handleBackwardsNavigation() async {
guard state.url != nil,
isPictureInPictureEnabled,
AVPictureInPictureController.isPictureInPictureSupported(),
let requestPictureInPictureHandler = state.bindings.requestPictureInPictureHandler else {
actionsSubject.send(.dismiss)
return
}

let controller = requestPictureInPictureHandler()
actionsSubject.send(.pictureInPictureStarted(controller))
switch await requestPictureInPictureHandler() {
case .success(let controller):
actionsSubject.send(.pictureInPictureStarted(controller))
case .failure:
actionsSubject.send(.dismiss)
}
}

private func setAudioEnabled(_ enabled: Bool) async {
Expand Down
37 changes: 26 additions & 11 deletions ElementX/Sources/Screens/CallScreen/View/CallScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private struct CallView: UIViewRepresentable {
private let certificateValidator: CertificateValidatorHookProtocol

private var webView: WKWebView!
private var pictureInPictureController: AVPictureInPictureController!
private var pictureInPictureController: AVPictureInPictureController?
private let pictureInPictureViewController: AVPictureInPictureVideoCallViewController

/// The view to be shown in the app. This will contain the web view when picture in picture isn't running.
Expand Down Expand Up @@ -132,9 +132,12 @@ private struct CallView: UIViewRepresentable {

webViewWrapper.addMatchedSubview(webView)

pictureInPictureController = .init(contentSource: .init(activeVideoCallSourceView: webViewWrapper,
contentViewController: pictureInPictureViewController))
pictureInPictureController.delegate = self
if AVPictureInPictureController.isPictureInPictureSupported() {
let pictureInPictureController = AVPictureInPictureController(contentSource: .init(activeVideoCallSourceView: webViewWrapper,
contentViewController: pictureInPictureViewController))
pictureInPictureController.delegate = self
self.pictureInPictureController = pictureInPictureController
}
}

func load(_ url: URL) {
Expand Down Expand Up @@ -205,20 +208,32 @@ private struct CallView: UIViewRepresentable {

// MARK: - Picture in Picture

func startPictureInPicture() -> AVPictureInPictureController {
pictureInPictureController.startPictureInPicture()
return pictureInPictureController
func startPictureInPicture() async -> Result<AVPictureInPictureController, CallScreenError> {
guard let pictureInPictureController, pictureInPictureController.isPictureInPicturePossible else {
return .failure(.pictureInPictureNotSupported)
}

do {
// Ideally we will replace this with a controls.isPipPossible call in the future.
_ = try await evaluateJavaScript("controls.enablePip()")
pictureInPictureController.startPictureInPicture()
return .success(pictureInPictureController)
} catch {
MXLog.error("Error starting picture in picture \(error)")
return .failure(.webViewError(error))
}
}

func stopPictureInPicture() {
pictureInPictureController.stopPictureInPicture()
pictureInPictureController?.stopPictureInPicture()
}

// Note: We handle moving the view via the delegate so it works when you background the app without calling startPictureInPicture
nonisolated func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
Task { @MainActor in
// We move the view via the delegate so it works when you background the app without calling startPictureInPicture
pictureInPictureViewController.view.addMatchedSubview(webView)
_ = try await evaluateJavaScript("controls.enablePip()")
// Similarly this is a redundant call when calling calling startPictureInPicture, but is necessary when backgrounding the app.
_ = try? await evaluateJavaScript("controls.enablePip()")
}
}

Expand All @@ -229,7 +244,7 @@ private struct CallView: UIViewRepresentable {
nonisolated func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
Task { @MainActor in
webViewWrapper.addMatchedSubview(webView)
_ = try await evaluateJavaScript("controls.disablePip()")
_ = try? await evaluateJavaScript("controls.disablePip()")
}
}
}
Expand Down

0 comments on commit eb0a84e

Please sign in to comment.