Files
iOS/Sources/App/Frontend/WebView/WebViewController+StatusBar.swift
2026-05-13 20:59:44 +00:00

121 lines
4.1 KiB
Swift

import Shared
import SwiftUI
import UIKit
@preconcurrency import WebKit
// MARK: - Status Bar & Toolbar
extension WebViewController {
func setupStatusBarView() -> UIView {
let statusBarView = UIView()
statusBarView.tag = 111
self.statusBarView = statusBarView
view.addSubview(statusBarView)
statusBarView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
statusBarView.topAnchor.constraint(equalTo: view.topAnchor),
statusBarView.leftAnchor.constraint(equalTo: view.leftAnchor),
statusBarView.rightAnchor.constraint(equalTo: view.rightAnchor),
statusBarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
])
if Current.isCatalyst {
setupStatusBarButtons(in: statusBarView)
}
return statusBarView
}
func setupStatusBarButtons(in statusBarView: UIView) {
// Remove existing stack if present
if let statusBarButtonsStack {
statusBarButtonsStack.removeFromSuperview()
self.statusBarButtonsStack = nil
}
let configuration = StatusBarButtonsConfigurator.Configuration(
server: server,
servers: Current.servers.all,
actions: .init(
refresh: { [weak self] in
self?.refresh()
},
openServer: { [weak self] server in
self?.openServer(server)
},
openInSafari: { [weak self] in
self?.openServerInSafari()
},
goBack: { [weak self] in
self?.goBack()
},
goForward: { [weak self] in
self?.goForward()
},
copy: { [weak self] in
self?.copyCurrentSelectedContent()
},
paste: { [weak self] in
self?.pasteContent()
}
)
)
statusBarButtonsStack = StatusBarButtonsConfigurator.setupButtons(
in: statusBarView,
configuration: configuration
)
}
func openServer(_ server: Server) {
Current.sceneManager.webViewWindowControllerPromise.done { controller in
controller.open(server: server)
}
}
@objc func openServerInSafari() {
if let url = webView.url {
guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return
}
// Remove external_auth=1 query item from URL
urlComponents.queryItems = urlComponents.queryItems?.filter { $0.name != "external_auth" }
if let url = urlComponents.url {
URLOpener.shared.open(url, options: [:], completionHandler: nil)
}
}
}
@objc func copyCurrentSelectedContent() {
// Get selected text from the web view
webView.evaluateJavaScript("window.getSelection().toString();") { result, error in
Current.Log
.error(
"Copy selected content result: \(String(describing: result)), error: \(String(describing: error))"
)
if let selectedText = result as? String, !selectedText.isEmpty {
// Copy to clipboard
UIPasteboard.general.string = selectedText
}
}
}
@objc func pasteContent() {
// Programmatically trigger the standard iOS paste action by calling the paste: selector
// This mimics the user selecting "Paste" from the context menu and allows paste to work properly
if webView.responds(to: #selector(paste(_:))) {
webView.perform(#selector(paste(_:)), with: nil)
}
}
@available(iOS 16.0, *)
@objc func showFindInteraction() {
// Present the find interaction UI
if let findInteraction = webView.findInteraction {
findInteraction.presentFindNavigator(showingReplace: false)
}
}
}