* Switch the TimelineController to an async sequence and fix the warnings on the UserIndicatorController
140 lines
5.1 KiB
Swift
140 lines
5.1 KiB
Swift
//
|
|
// Copyright 2022-2024 New Vector Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Compound
|
|
import SwiftUI
|
|
import WebKit
|
|
|
|
struct WebRegistrationScreen: View {
|
|
@ObservedObject var context: WebRegistrationScreenViewModel.Context
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
WebRegistrationWebView(url: context.viewState.url, viewModelContext: context)
|
|
.navigationTitle(L10n.screenCreateAccountTitle)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbarBackground(.visible, for: .navigationBar)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button(L10n.actionCancel) {
|
|
context.send(viewAction: .cancel)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct WebRegistrationWebView: UIViewRepresentable {
|
|
let url: URL
|
|
let viewModelContext: WebRegistrationScreenViewModel.Context
|
|
|
|
func makeUIView(context: Context) -> WKWebView {
|
|
context.coordinator.webView
|
|
}
|
|
|
|
func updateUIView(_ webView: WKWebView, context: Context) { }
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(url: url, viewModelContext: viewModelContext)
|
|
}
|
|
|
|
class Coordinator: NSObject, WKUIDelegate {
|
|
private let url: URL
|
|
private let viewModelContext: WebRegistrationScreenViewModel.Context
|
|
|
|
private(set) var webView: WKWebView!
|
|
|
|
init(url: URL, viewModelContext: WebRegistrationScreenViewModel.Context) {
|
|
self.url = url
|
|
self.viewModelContext = viewModelContext
|
|
|
|
super.init()
|
|
|
|
let eventHandlerName = "elementx"
|
|
let userContentController = WKUserContentController()
|
|
userContentController.add(WKScriptMessageHandlerWrapper(self), name: eventHandlerName)
|
|
|
|
let eventHandlerScript = """
|
|
window.addEventListener(
|
|
"mobileregistrationresponse",
|
|
(event) => {
|
|
window.webkit.messageHandlers.\(eventHandlerName).postMessage(JSON.stringify(event.detail));
|
|
},
|
|
false,
|
|
);
|
|
"""
|
|
|
|
let userScript = WKUserScript(source: eventHandlerScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
|
|
userContentController.addUserScript(userScript)
|
|
|
|
let configuration = WKWebViewConfiguration()
|
|
configuration.userContentController = userContentController
|
|
configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
|
|
|
|
webView = WKWebView(frame: .zero, configuration: configuration)
|
|
webView.uiDelegate = self
|
|
webView.load(URLRequest(url: url))
|
|
}
|
|
|
|
func userContentController(_ userContentController: WKUserContentController,
|
|
didReceive message: WKScriptMessage) {
|
|
guard let jsonString = message.body as? String, let jsonData = jsonString.data(using: .utf8) else {
|
|
MXLog.error("Unexpected response.")
|
|
return
|
|
}
|
|
|
|
guard let credentials = try? JSONDecoder().decode(WebRegistrationCredentials.self, from: jsonData) else {
|
|
MXLog.error("Invalid response.")
|
|
return
|
|
}
|
|
|
|
MXLog.info("Received login credentials.")
|
|
viewModelContext.send(viewAction: .signedIn(credentials))
|
|
}
|
|
|
|
// MARK: WKUIDelegate
|
|
|
|
func webView(_ webView: WKWebView,
|
|
createWebViewWith configuration: WKWebViewConfiguration,
|
|
for navigationAction: WKNavigationAction,
|
|
windowFeatures: WKWindowFeatures) -> WKWebView? {
|
|
if let url = navigationAction.request.url, UIApplication.shared.canOpenURL(url) {
|
|
UIApplication.shared.open(url)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Avoids retain loops between the configuration and webView coordinator
|
|
private class WKScriptMessageHandlerWrapper: NSObject, WKScriptMessageHandler {
|
|
private weak var coordinator: Coordinator?
|
|
|
|
init(_ coordinator: Coordinator) {
|
|
self.coordinator = coordinator
|
|
}
|
|
|
|
// MARK: WKScriptMessageHandler
|
|
|
|
func userContentController(_ userContentController: WKUserContentController,
|
|
didReceive message: WKScriptMessage) {
|
|
coordinator?.userContentController(userContentController, didReceive: message)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Previews
|
|
|
|
struct WebRegistrationScreen_Previews: PreviewProvider {
|
|
static let viewModel = WebRegistrationScreenViewModel(registrationHelperURL: "https://develop.element.io/#/mobile_register")
|
|
static var previews: some View {
|
|
NavigationStack {
|
|
WebRegistrationScreen(context: viewModel.context)
|
|
}
|
|
}
|
|
}
|