diff --git a/ElementX/Sources/Screens/CallScreen/CallScreenModels.swift b/ElementX/Sources/Screens/CallScreen/CallScreenModels.swift index b0a425ca7..cda28738f 100644 --- a/ElementX/Sources/Screens/CallScreen/CallScreenModels.swift +++ b/ElementX/Sources/Screens/CallScreen/CallScreenModels.swift @@ -21,6 +21,8 @@ struct CallScreenViewState: BindableState { var url: URL? var bindings = Bindings() + + var swiftUICallViewCoordinator: CallView.Coordinator? } struct Bindings { diff --git a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift index 78bb60e0e..5fcc2e5a9 100644 --- a/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift +++ b/ElementX/Sources/Screens/CallScreen/CallScreenViewModel.swift @@ -52,6 +52,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol super.init(initialViewState: CallScreenViewState(script: CallScreenJavaScriptMessageName.allCasesInjectionScript)) + state.swiftUICallViewCoordinator = .init(viewModelContext: context) + elementCallService.actions .receive(on: DispatchQueue.main) .sink { [weak self] action in diff --git a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift index 9d591288e..b0ecc383b 100644 --- a/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift +++ b/ElementX/Sources/Screens/CallScreen/View/CallScreen.swift @@ -53,7 +53,7 @@ struct CallScreen: View { } } -private struct CallView: UIViewRepresentable { +struct CallView: UIViewRepresentable { /// The top-level view this representable displays. It wraps the web view when picture in picture isn't running. typealias WebViewWrapper = UIView @@ -65,7 +65,13 @@ private struct CallView: UIViewRepresentable { } func makeCoordinator() -> Coordinator { - Coordinator(viewModelContext: viewModelContext) + if let existing = viewModelContext.viewState.swiftUICallViewCoordinator { + return existing + } + // When the screen is rotated, the pro max models regenerate the swiftui view tree, destroying and + // rebuilding this view. For that reason, we need to create and store the coordinator in the view model + // (and by extension the UIView) to persist between rotations to retain state + fatalError("CallView.Coordinator must be initialized in the context view state") } func updateUIView(_ callWebView: WebViewWrapper, context: Context) { @@ -151,6 +157,7 @@ private struct CallView: UIViewRepresentable { } func load(_ url: URL) { + guard self.url != url else { return } self.url = url // The only file URL we allow is the one coming from our own local ElementCall bundle, so it's okay to allow read permission only to our local EC bundle if url.isFileURL {