Fix several concurrency warnings.
This commit is contained in:
parent
cc71152b16
commit
79c2f4c7f5
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import WebKit
|
import WebKit
|
||||||
@preconcurrency import Images
|
import Images
|
||||||
|
|
||||||
protocol ArticleIconSchemeHandlerDelegate: AnyObject {
|
protocol ArticleIconSchemeHandlerDelegate: AnyObject {
|
||||||
|
|
||||||
func iconImage(for articleID: String) -> IconImage?
|
@MainActor func iconImage(for articleID: String) -> IconImage?
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ArticleIconSchemeHandler: NSObject, WKURLSchemeHandler {
|
final class ArticleIconSchemeHandler: NSObject, WKURLSchemeHandler {
|
||||||
@ -34,31 +34,34 @@ final class ArticleIconSchemeHandler: NSObject, WKURLSchemeHandler {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let articleID = components.path
|
let articleID = components.path
|
||||||
guard let iconImage = delegate.iconImage(for: articleID) else {
|
|
||||||
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Task { @MainActor in
|
MainActor.assumeIsolated {
|
||||||
|
guard let iconImage = delegate.iconImage(for: articleID) else {
|
||||||
let iconView = IconView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
|
|
||||||
iconView.iconImage = iconImage
|
|
||||||
let renderedImage = iconView.asImage()
|
|
||||||
|
|
||||||
guard let data = renderedImage.dataRepresentation() else {
|
|
||||||
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let headerFields = ["Cache-Control": "no-cache"]
|
Task { @MainActor in
|
||||||
if let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: headerFields) {
|
|
||||||
urlSchemeTask.didReceive(response)
|
let iconView = IconView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))
|
||||||
urlSchemeTask.didReceive(data)
|
iconView.iconImage = iconImage
|
||||||
urlSchemeTask.didFinish()
|
let renderedImage = iconView.asImage()
|
||||||
|
|
||||||
|
guard let data = renderedImage.dataRepresentation() else {
|
||||||
|
urlSchemeTask.didFailWithError(URLError(.fileDoesNotExist))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let headerFields = ["Cache-Control": "no-cache"]
|
||||||
|
if let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: headerFields) {
|
||||||
|
urlSchemeTask.didReceive(response)
|
||||||
|
urlSchemeTask.didReceive(data)
|
||||||
|
urlSchemeTask.didFinish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
|
||||||
urlSchemeTask.didFailWithError(URLError(.unknown))
|
urlSchemeTask.didFailWithError(URLError(.unknown))
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import MessageUI
|
|||||||
import Core
|
import Core
|
||||||
import ArticleExtractor
|
import ArticleExtractor
|
||||||
import Images
|
import Images
|
||||||
|
import Web
|
||||||
|
|
||||||
protocol WebViewControllerDelegate: AnyObject {
|
protocol WebViewControllerDelegate: AnyObject {
|
||||||
|
|
||||||
@ -388,81 +389,110 @@ extension WebViewController: UIContextMenuInteractionDelegate {
|
|||||||
|
|
||||||
extension WebViewController: WKNavigationDelegate {
|
extension WebViewController: WKNavigationDelegate {
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
nonisolated func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||||
|
|
||||||
if navigationAction.navigationType == .linkActivated {
|
guard navigationAction.navigationType == .linkActivated else {
|
||||||
guard let url = navigationAction.request.url else {
|
decisionHandler(.allow)
|
||||||
decisionHandler(.allow)
|
return
|
||||||
|
}
|
||||||
|
guard let url = navigationAction.request.url else {
|
||||||
|
decisionHandler(.allow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let scheme = components.scheme else {
|
||||||
|
decisionHandler(.allow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch scheme {
|
||||||
|
|
||||||
|
case URLScheme.http, URLScheme.https:
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
openURLInBrowser(url)
|
||||||
|
|
||||||
|
case URLScheme.mailto:
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
guard let emailAddressURL = url.percentEncodedEmailAddress else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
openEmailAddressURL(emailAddressURL)
|
||||||
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
|
||||||
if components?.scheme == "http" || components?.scheme == "https" {
|
case URLScheme.tel:
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
if AppDefaults.shared.useSystemBrowser {
|
openTelURL(url)
|
||||||
UIApplication.shared.open(url, options: [:])
|
|
||||||
} else {
|
default:
|
||||||
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { didOpen in
|
|
||||||
guard didOpen == false else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let vc = SFSafariViewController(url: url)
|
|
||||||
self.present(vc, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if components?.scheme == "mailto" {
|
|
||||||
decisionHandler(.cancel)
|
|
||||||
|
|
||||||
guard let emailAddress = url.percentEncodedEmailAddress else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if UIApplication.shared.canOpenURL(emailAddress) {
|
|
||||||
UIApplication.shared.open(emailAddress, options: [.universalLinksOnly : false], completionHandler: nil)
|
|
||||||
} else {
|
|
||||||
let alert = UIAlertController(title: NSLocalizedString("Error", comment: "Error"), message: NSLocalizedString("This device cannot send emails.", comment: "This device cannot send emails."), preferredStyle: .alert)
|
|
||||||
alert.addAction(.init(title: NSLocalizedString("Dismiss", comment: "Dismiss"), style: .cancel, handler: nil))
|
|
||||||
self.present(alert, animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
} else if components?.scheme == "tel" {
|
|
||||||
decisionHandler(.cancel)
|
|
||||||
|
|
||||||
if UIApplication.shared.canOpenURL(url) {
|
|
||||||
UIApplication.shared.open(url, options: [.universalLinksOnly : false], completionHandler: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
decisionHandler(.allow)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
decisionHandler(.allow)
|
decisionHandler(.allow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
|
nonisolated func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
|
||||||
fullReload()
|
|
||||||
|
Task { @MainActor in
|
||||||
|
fullReload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated private func openURLInBrowser(_ url: URL) {
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
if AppDefaults.shared.useSystemBrowser {
|
||||||
|
UIApplication.shared.open(url, options: [:])
|
||||||
|
} else {
|
||||||
|
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { didOpen in
|
||||||
|
guard didOpen == false else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let vc = SFSafariViewController(url: url)
|
||||||
|
self.present(vc, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated private func openEmailAddressURL(_ url: URL) {
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
if UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url, options: [.universalLinksOnly : false], completionHandler: nil)
|
||||||
|
} else {
|
||||||
|
let alert = UIAlertController(title: NSLocalizedString("Error", comment: "Error"), message: NSLocalizedString("This device cannot send emails.", comment: "This device cannot send emails."), preferredStyle: .alert)
|
||||||
|
alert.addAction(.init(title: NSLocalizedString("Dismiss", comment: "Dismiss"), style: .cancel, handler: nil))
|
||||||
|
self.present(alert, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonisolated private func openTelURL(_ url: URL) {
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
if UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url, options: [.universalLinksOnly : false], completionHandler: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: WKUIDelegate
|
// MARK: WKUIDelegate
|
||||||
|
|
||||||
extension WebViewController: WKUIDelegate {
|
extension WebViewController: WKUIDelegate {
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, contextMenuForElement elementInfo: WKContextMenuElementInfo, willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
|
nonisolated func webView(_ webView: WKWebView, contextMenuForElement elementInfo: WKContextMenuElementInfo, willCommitWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
|
||||||
// We need to have at least an unimplemented WKUIDelegate assigned to the WKWebView. This makes the
|
// We need to have at least an unimplemented WKUIDelegate assigned to the WKWebView. This makes the
|
||||||
// link preview launch Safari when the link preview is tapped. In theory, you should be able to get
|
// link preview launch Safari when the link preview is tapped. In theory, you should be able to get
|
||||||
// the link from the elementInfo above and transition to SFSafariViewController instead of launching
|
// the link from the elementInfo above and transition to SFSafariViewController instead of launching
|
||||||
// Safari. As the time of this writing, the link in elementInfo is always nil. ¯\_(ツ)_/¯
|
// Safari. As the time of this writing, the link in elementInfo is always nil. ¯\_(ツ)_/¯
|
||||||
}
|
}
|
||||||
|
|
||||||
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
nonisolated func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||||
guard let url = navigationAction.request.url else {
|
guard let url = navigationAction.request.url else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
openURL(url)
|
Task { @MainActor in
|
||||||
|
openURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,18 +502,24 @@ extension WebViewController: WKUIDelegate {
|
|||||||
|
|
||||||
extension WebViewController: WKScriptMessageHandler {
|
extension WebViewController: WKScriptMessageHandler {
|
||||||
|
|
||||||
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
nonisolated func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||||
switch message.name {
|
|
||||||
case MessageName.imageWasShown:
|
let name = message.name
|
||||||
clickedImageCompletion?()
|
let body = message.body as? String
|
||||||
case MessageName.imageWasClicked:
|
|
||||||
imageWasClicked(body: message.body as? String)
|
Task { @MainActor in
|
||||||
case MessageName.showFeedInspector:
|
switch name {
|
||||||
if let feed = article?.feed {
|
case MessageName.imageWasShown:
|
||||||
coordinator.showFeedInspector(for: feed)
|
clickedImageCompletion?()
|
||||||
|
case MessageName.imageWasClicked:
|
||||||
|
imageWasClicked(body: body)
|
||||||
|
case MessageName.showFeedInspector:
|
||||||
|
if let feed = article?.feed {
|
||||||
|
coordinator.showFeedInspector(for: feed)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user