Files
iOS/Sources/App/Frontend/WebView/WebViewController+ProtocolConformance.swift
Bruno Pantaleão Gonçalves 6e22a09338 Prevent duplicate error message when HA unreachable (#4546)
<!-- 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. -->
<img width="1206" height="2622" alt="Simulator Screenshot - Daily tester
2 - 2026-04-22 at 14 43 08"
src="https://github.com/user-attachments/assets/66e0e557-5b69-4f8d-82c1-53dbf7fb4b9b"
/>

## 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. -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-04-22 15:40:52 +02:00

136 lines
4.2 KiB
Swift

import Foundation
import Shared
import UIKit
import WebKit
extension WebViewController: WebViewControllerProtocol {
var canGoBack: Bool {
webView.canGoBack
}
var canGoForward: Bool {
webView.canGoForward
}
@objc func goBack() {
webView.goBack()
}
@objc func goForward() {
webView.goForward()
}
var overlayedController: UIViewController? {
presentedViewController
}
func presentOverlayController(controller: UIViewController, animated: Bool) {
DispatchQueue.main.async { [weak self] in
self?.dismissOverlayController(animated: false, completion: { [weak self] in
self?.present(controller, animated: animated, completion: nil)
})
}
}
func presentAlertController(controller: UIViewController, animated: Bool) {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
if let overlayedController {
overlayedController.present(controller, animated: animated, completion: nil)
} else {
present(controller, animated: animated, completion: nil)
}
}
}
func evaluateJavaScript(_ script: String, completion: ((Any?, (any Error)?) -> Void)?) {
webView.evaluateJavaScript(script, completionHandler: completion)
}
func dismissOverlayController(animated: Bool, completion: (() -> Void)?) {
dismissAllViewControllersAbove(completion: completion)
}
func dismissControllerAboveOverlayController() {
overlayedController?.dismissAllViewControllersAbove()
}
func updateFrontendConnectionState(state: String) {
emptyStateTimer?.invalidate()
emptyStateTimer = nil
latestLoadError = nil
let requestedState = FrontEndConnectionState(rawValue: state) ?? .unknown
let resolvedState: FrontEndConnectionState = if connectionState == .authInvalid, requestedState != .connected {
.authInvalid
} else {
requestedState
}
isConnected = resolvedState == .connected
connectionState = resolvedState
// Possible values: connected, disconnected, auth-invalid
switch resolvedState {
case .connected:
hideEmptyState()
case .authInvalid:
showEmptyState()
case .disconnected, .unknown:
// Start a 10-second timer. If not interrupted by a 'connected' state, set alpha to 1.
emptyStateTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [weak self] _ in
self?.showEmptyState()
}
}
}
func navigateToPath(path: String) {
if let activeURL = server.info.connection.activeURL(), let url = URL(string: activeURL.absoluteString + path) {
load(request: URLRequest(url: url))
}
}
func showBanner(request: BannerRequest) {
bannerPresenter.show(on: self, request: request)
}
func hideBanner(id: String) {
bannerPresenter.hide(id: id)
}
func load(request: URLRequest) {
Current.Log.verbose("Requesting webView navigation to \(String(describing: request.url?.absoluteString))")
webView.load(request)
}
@objc func refresh() {
let refreshBlock: () -> Void = { [weak self] in
guard let self else { return }
// called via menu/keyboard shortcut too
if let webviewURL = server.info.connection.webviewURL() {
if webView.url?.baseIsEqual(to: webviewURL) == true, !lastNavigationWasServerError {
reload()
} else {
load(request: URLRequest(url: webviewURL))
}
hideNoActiveURLError()
} else {
showNoActiveURLError()
}
}
if Current.isCatalyst {
refreshBlock()
} else {
Current.connectivity.syncNetworkInformation {
refreshBlock()
}
}
updateDatabaseAndPanels()
}
@objc func refreshIfDisconnected() {
guard connectionState != .connected else { return }
refresh()
}
}