Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Update async-await
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon-T authored and soner-yuksel committed Nov 30, 2023
1 parent 94553d4 commit c393f8d
Showing 1 changed file with 143 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,44 +179,28 @@ extension BrowserViewController: WKNavigationDelegate {
let tab = tab(for: webView)

if ["sms", "tel", "facetime", "facetime-audio"].contains(requestURL.scheme) {
// Do not allow opening external URLs from child tabs
return await withCheckedContinuation { continuation in
handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction) { shouldOpen in
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}
let shouldOpen = await handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction)
return (shouldOpen ? .allow : .cancel, preferences)
}

// Second special case are a set of URLs that look like regular http links, but should be handed over to iOS
// instead of being loaded in the webview.
// In addition we are exchaging actual scheme with "maps" scheme
// So the Apple maps URLs will open properly
if let mapsURL = isAppleMapsURL(requestURL), mapsURL.enabled {
// Do not allow opening external URLs from child tabs
return await withCheckedContinuation { continuation in
handleExternalURL(mapsURL.url, tab: tab, navigationAction: navigationAction) { shouldOpen in
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}
let shouldOpen = await handleExternalURL(mapsURL.url, tab: tab, navigationAction: navigationAction)
return (shouldOpen ? .allow : .cancel, preferences)
}

if isStoreURL(requestURL) {
// Do not allow opening external URLs from child tabs
return await withCheckedContinuation { continuation in
handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction) { shouldOpen in
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}
let shouldOpen = await handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction)
return (shouldOpen ? .allow : .cancel, preferences)
}

// Handles custom mailto URL schemes.
if requestURL.scheme == "mailto" {
// Do not allow opening external URLs from child tabs
return await withCheckedContinuation { continuation in
handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction) { shouldOpen in
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}
let shouldOpen = await handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction)
return (shouldOpen ? .allow : .cancel, preferences)
}

// handles IPFS URL schemes
Expand Down Expand Up @@ -418,30 +402,29 @@ extension BrowserViewController: WKNavigationDelegate {
// Our own 'brave' scheme does not require the switch-app prompt.
if requestURL.scheme?.contains("brave") == false {
// Do not allow opening external URLs from child tabs
return await withCheckedContinuation { continuation in
handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction) { [weak tab] shouldOpen in

let isSyntheticClick = navigationAction.responds(to: Selector(("_syntheticClickType"))) && navigationAction.value(forKey: "syntheticClickType") as? Int == 0
let shouldOpen = await handleExternalURL(requestURL, tab: tab, navigationAction: navigationAction)
let isSyntheticClick = navigationAction.responds(to: Selector(("_syntheticClickType"))) &&
navigationAction.value(forKey: "syntheticClickType") as? Int == 0

// Do not show error message for JS navigated links or redirect
// as it's not the result of a user action.
if !shouldOpen, navigationAction.navigationType == .linkActivated && !isSyntheticClick {
if self.presentedViewController == nil &&
self.presentingViewController == nil &&
tab?.isExternalAppAlertPresented == false &&
tab?.isExternalAppAlertSuppressed == false {

// Do not show error message for JS navigated links or redirect
// as it's not the result of a user action.
if !shouldOpen, navigationAction.navigationType == .linkActivated && !isSyntheticClick {
if self.presentedViewController == nil &&
self.presentingViewController == nil &&
tab?.isExternalAppAlertPresented == false &&
tab?.isExternalAppAlertSuppressed == false {
let alert = UIAlertController(title: Strings.unableToOpenURLErrorTitle, message: Strings.unableToOpenURLError, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Strings.OKString, style: .default, handler: nil))
self.present(alert, animated: true) {
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
return
return await withCheckedContinuation { continuation in
let alert = UIAlertController(title: Strings.unableToOpenURLErrorTitle, message: Strings.unableToOpenURLError, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: Strings.OKString, style: .default, handler: nil))
self.present(alert, animated: true) {
continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}

continuation.resume(returning: (shouldOpen ? .allow : .cancel, preferences))
}
}

return (shouldOpen ? .allow : .cancel, preferences)
}

return (.cancel, preferences)
Expand Down Expand Up @@ -824,136 +807,139 @@ extension BrowserViewController {
private func handleExternalURL(
_ url: URL,
tab: Tab?,
navigationAction: WKNavigationAction,
openedURLCompletionHandler: ((Bool) -> Void)? = nil
) {
// Do not open external links for child tabs automatically
// The user must tap on the link to open it.
if tab?.parent != nil && navigationAction.navigationType != .linkActivated {
openedURLCompletionHandler?(false)
return
}

// Check if the current url of the caller has changed
if let domain = tab?.url?.baseDomain,
domain != tab?.externalAppURLDomain {
tab?.externalAppAlertCounter = 0
tab?.isExternalAppAlertSuppressed = false
}
tab?.externalAppURLDomain = tab?.url?.baseDomain

// Do not try to present over existing warning
if tab?.isExternalAppAlertPresented == true || tab?.isExternalAppAlertSuppressed == true {
openedURLCompletionHandler?(false)
return
}

// External dialog should not be shown for non-active tabs #6687 - #7835
let isVisibleTab = tab?.isTabVisible() == true

// Check user trying to open on NTP like external link browsing
var isAboutHome = false
if let url = tab?.url {
isAboutHome = InternalURL(url)?.isAboutHomeURL == true
}

// Finally check non-active tab
let isNonActiveTab = isAboutHome ? false : tab?.url?.host != topToolbar.currentURL?.host

if !isVisibleTab || isNonActiveTab {
openedURLCompletionHandler?(false)
return
}

var alertTitle = Strings.openExternalAppURLGenericTitle

if let displayHost = tab?.url?.withoutWWW.host {
alertTitle = String(format: Strings.openExternalAppURLTitle, displayHost)
}

// Handling condition when Tab is empty when handling an external URL we should remove the tab once the user decides
let removeTabIfEmpty = { [weak self] in
if let tab = tab, tab.url == nil {
self?.tabManager.removeTab(tab)
navigationAction: WKNavigationAction) async -> Bool {
// Do not open external links for child tabs automatically
// The user must tap on the link to open it.
if tab?.parent != nil && navigationAction.navigationType != .linkActivated {
return false
}
}

// Show the external sceheme invoke alert
func showExternalSchemeAlert(isSuppressActive: Bool) {
// Check if active controller is bvc otherwise do not show show external sceheme alerts
guard shouldShowExternalSchemeAlert() else {
openedURLCompletionHandler?(false)
return

// Check if the current url of the caller has changed
if let domain = tab?.url?.baseDomain,
domain != tab?.externalAppURLDomain {
tab?.externalAppAlertCounter = 0
tab?.isExternalAppAlertSuppressed = false
}

view.endEditing(true)
tab?.isExternalAppAlertPresented = true

let popup = AlertPopupView(
imageView: nil,
title: alertTitle,
message: String(format: Strings.openExternalAppURLMessage, url.relativeString),
titleWeight: .semibold,
titleSize: 21
)
if isSuppressActive {
popup.addButton(title: Strings.suppressAlertsActionTitle, type: .destructive) { [weak tab] () -> PopupViewDismissType in
openedURLCompletionHandler?(false)
tab?.isExternalAppAlertSuppressed = true
return .flyDown
tab?.externalAppURLDomain = tab?.url?.baseDomain

// Do not try to present over existing warning
if tab?.isExternalAppAlertPresented == true || tab?.isExternalAppAlertSuppressed == true {
return false
}

// External dialog should not be shown for non-active tabs #6687 - #7835
let isVisibleTab = tab?.isTabVisible() == true

// Check user trying to open on NTP like external link browsing
var isAboutHome = false
if let url = tab?.url {
isAboutHome = InternalURL(url)?.isAboutHomeURL == true
}

// Finally check non-active tab
let isNonActiveTab = isAboutHome ? false : tab?.url?.host != topToolbar.currentURL?.host

if !isVisibleTab || isNonActiveTab {
return false
}

var alertTitle = Strings.openExternalAppURLGenericTitle

if let displayHost = tab?.url?.withoutWWW.host {
alertTitle = String(format: Strings.openExternalAppURLTitle, displayHost)
}

// Handling condition when Tab is empty when handling an external URL we should remove the tab once the user decides
let removeTabIfEmpty = { [weak self] in
if let tab = tab, tab.url == nil {
self?.tabManager.removeTab(tab)
}
} else {
popup.addButton(title: Strings.openExternalAppURLDontAllow) { [weak tab] () -> PopupViewDismissType in
openedURLCompletionHandler?(false)
}

// Show the external sceheme invoke alert
@MainActor
func showExternalSchemeAlert(isSuppressActive: Bool, openedURLCompletionHandler: @escaping (Bool) -> Void) {
// Check if active controller is bvc otherwise do not show show external sceheme alerts
guard shouldShowExternalSchemeAlert() else {
openedURLCompletionHandler(false)
return
}

view.endEditing(true)
tab?.isExternalAppAlertPresented = true

let popup = AlertPopupView(
imageView: nil,
title: alertTitle,
message: String(format: Strings.openExternalAppURLMessage, url.relativeString),
titleWeight: .semibold,
titleSize: 21
)

if isSuppressActive {
popup.addButton(title: Strings.suppressAlertsActionTitle, type: .destructive) { [weak tab] () -> PopupViewDismissType in
openedURLCompletionHandler(false)
tab?.isExternalAppAlertSuppressed = true
return .flyDown
}
} else {
popup.addButton(title: Strings.openExternalAppURLDontAllow) { [weak tab] () -> PopupViewDismissType in
openedURLCompletionHandler(false)
removeTabIfEmpty()
tab?.isExternalAppAlertPresented = false
return .flyDown
}
}
popup.addButton(title: Strings.openExternalAppURLAllow, type: .primary) { [weak tab] () -> PopupViewDismissType in
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:]) { didOpen in
openedURLCompletionHandler(!didOpen)
}
} else {
openedURLCompletionHandler(true)
}
removeTabIfEmpty()
tab?.isExternalAppAlertPresented = false
return .flyDown
}
popup.showWithType(showType: .flyUp)
}
popup.addButton(title: Strings.openExternalAppURLAllow, type: .primary) { [weak tab] () -> PopupViewDismissType in
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:]) { didOpen in
openedURLCompletionHandler?(!didOpen)

func shouldShowExternalSchemeAlert() -> Bool {
guard let rootVC = currentScene?.browserViewController else {
return false
}

func topViewController(startingFrom viewController: UIViewController) -> UIViewController {
var top = viewController
if let navigationController = top as? UINavigationController,
let vc = navigationController.visibleViewController {
return topViewController(startingFrom: vc)
}
} else {
openedURLCompletionHandler?(true)
if let tabController = top as? UITabBarController,
let vc = tabController.selectedViewController {
return topViewController(startingFrom: vc)
}
while let next = top.presentedViewController {
top = next
}
return top
}
removeTabIfEmpty()
tab?.isExternalAppAlertPresented = false
return .flyDown
}
popup.showWithType(showType: .flyUp)
}

func shouldShowExternalSchemeAlert() -> Bool {
guard let rootVC = currentScene?.browserViewController else {
return false

let isTopController = self == topViewController(startingFrom: rootVC)
let isTopWindow = view.window?.isKeyWindow == true
return isTopController && isTopWindow
}

func topViewController(startingFrom viewController: UIViewController) -> UIViewController {
var top = viewController
if let navigationController = top as? UINavigationController,
let vc = navigationController.visibleViewController {
return topViewController(startingFrom: vc)
}
if let tabController = top as? UITabBarController,
let vc = tabController.selectedViewController {
return topViewController(startingFrom: vc)
}
while let next = top.presentedViewController {
top = next
tab?.externalAppAlertCounter += 1

return await withCheckedContinuation { continuation in
showExternalSchemeAlert(isSuppressActive: tab?.externalAppAlertCounter ?? 0 > 2) {
continuation.resume(with: .success($0))
}
return top
}

let isTopController = self == topViewController(startingFrom: rootVC)
let isTopWindow = view.window?.isKeyWindow == true
return isTopController && isTopWindow
}

tab?.externalAppAlertCounter += 1
showExternalSchemeAlert(isSuppressActive: tab?.externalAppAlertCounter ?? 0 > 2)
}
}

// MARK: WKUIDelegate
Expand Down

0 comments on commit c393f8d

Please sign in to comment.