Add mac server quick switch picker and button to open current page in external browser (#3407)

<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->
![CleanShot 2025-02-05 at 15 38
01@2x](https://github.com/user-attachments/assets/c9ef5733-3bd3-4d58-99c5-bccea1367a92)

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
This commit is contained in:
Bruno Pantaleão Gonçalves
2025-02-05 16:23:28 +01:00
committed by GitHub
parent ddb696d2e1
commit 503a3394d6
3 changed files with 92 additions and 7 deletions

View File

@@ -1162,4 +1162,5 @@ Home Assistant is free and open source home automation software with a focus on
"widgets.sensors.description" = "Display state of sensors";
"widgets.sensors.not_configured" = "No Sensors Configured";
"widgets.sensors.title" = "Sensors";
"yes_label" = "Yes";
"web_view.server_selection.title" = "Choose server";
"yes_label" = "Yes";

View File

@@ -40,6 +40,7 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg
let webViewExternalMessageHandler = WebViewExternalMessageHandler.build()
private var initialURL: URL?
private var statusBarButtonsStack: UIStackView?
/// A view controller presented by a request from the webview
var overlayAppController: UIViewController?
@@ -236,16 +237,92 @@ final class WebViewController: UIViewController, WKNavigationDelegate, WKUIDeleg
statusBarView.tag = 111
view.addSubview(statusBarView)
statusBarView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
statusBarView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
statusBarView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
statusBarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
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(statusBarView: statusBarView)
}
return statusBarView
}
private func setupStatusBarButtons(statusBarView: UIView) {
let picker = UIButton(type: .system)
picker.setTitle(server.info.name, for: .normal)
picker.translatesAutoresizingMaskIntoConstraints = false
let menuActions = Current.servers.all.map { server in
UIAction(title: server.info.name, handler: { [weak self] _ in
self?.openServer(server)
})
}
// Using UIMenu since UIPickerView is not available on Catalyst
picker.menu = UIMenu(title: L10n.WebView.ServerSelection.title, children: menuActions)
picker.showsMenuAsPrimaryAction = true
let openInSafariButton = UIButton(type: .detailDisclosure)
openInSafariButton.setImage(UIImage(systemSymbol: .safari), for: .normal)
openInSafariButton.backgroundColor = .systemBackground
openInSafariButton.tintColor = Asset.Colors.haPrimary.color
openInSafariButton.layer.cornerRadius = 10
openInSafariButton.addTarget(self, action: #selector(openServerInSafari), for: .touchUpInside)
if let statusBarButtonsStack {
statusBarButtonsStack.removeFromSuperview()
self.statusBarButtonsStack = nil
}
let arrangedSubviews: [UIView] = {
if Current.servers.all.count > 1 {
return [picker, openInSafariButton]
} else {
// No need to display server picker
return [openInSafariButton]
}
}()
let stackView = UIStackView(arrangedSubviews: arrangedSubviews)
stackView.axis = .horizontal
stackView.spacing = Spaces.one
statusBarView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.rightAnchor.constraint(equalTo: statusBarView.rightAnchor, constant: -Spaces.half),
stackView.topAnchor.constraint(equalTo: statusBarView.topAnchor, constant: Spaces.half),
])
statusBarButtonsStack = stackView
}
private func openServer(_ server: Server) {
Current.sceneManager.webViewWindowControllerPromise.done { controller in
controller.open(server: server)
}
}
@objc private 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 {
UIApplication.shared.open(url)
}
}
}
public func showSettingsViewController() {
getLatestConfig()
if Current.sceneManager.supportsMultipleScenes, Current.isCatalyst {

View File

@@ -3817,6 +3817,13 @@ public enum L10n {
}
}
public enum WebView {
public enum ServerSelection {
/// Choose server
public static var title: String { return L10n.tr("Localizable", "web_view.server_selection.title") }
}
}
public enum Widgets {
public enum Action {
public enum Name {