Create CallView.Coordinator in ViewModel

preserving it across view rebuilds as phone rotates
This commit is contained in:
mredig
2026-08-05 02:07:18 -05:00
committed by Mauro
parent 668fbe1827
commit bbdbbe1081
3 changed files with 13 additions and 2 deletions
@@ -21,6 +21,8 @@ struct CallScreenViewState: BindableState {
var url: URL? var url: URL?
var bindings = Bindings() var bindings = Bindings()
var swiftUICallViewCoordinator: CallView.Coordinator?
} }
struct Bindings { struct Bindings {
@@ -52,6 +52,8 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
super.init(initialViewState: CallScreenViewState(script: CallScreenJavaScriptMessageName.allCasesInjectionScript)) super.init(initialViewState: CallScreenViewState(script: CallScreenJavaScriptMessageName.allCasesInjectionScript))
state.swiftUICallViewCoordinator = .init(viewModelContext: context)
elementCallService.actions elementCallService.actions
.receive(on: DispatchQueue.main) .receive(on: DispatchQueue.main)
.sink { [weak self] action in .sink { [weak self] action in
@@ -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. /// The top-level view this representable displays. It wraps the web view when picture in picture isn't running.
typealias WebViewWrapper = UIView typealias WebViewWrapper = UIView
@@ -65,7 +65,13 @@ private struct CallView: UIViewRepresentable {
} }
func makeCoordinator() -> Coordinator { 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) { func updateUIView(_ callWebView: WebViewWrapper, context: Context) {
@@ -151,6 +157,7 @@ private struct CallView: UIViewRepresentable {
} }
func load(_ url: URL) { func load(_ url: URL) {
guard self.url != url else { return }
self.url = url 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 // 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 { if url.isFileURL {