mirror of
https://github.com/home-assistant/iOS.git
synced 2026-04-12 05:08:23 -05:00
Split WebViewController functionality into multiple extension files (Alerts, EmptyState, Gestures, Navigation, Onboarding, Settings, StatusBar, URLLoading, WebViewSetup) and add FrontEndConnectionState enum. Update Xcode project to include the new source files and adjust several Database test file references and a local Swift package path (Sources/SharedPush). Also add empty input/output path arrays to several CocoaPods embed phases. This refactors web view features into modular components and wires them into the project file. <!-- 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. --> ## 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. -->
147 lines
5.6 KiB
Swift
147 lines
5.6 KiB
Swift
import PromiseKit
|
|
import Shared
|
|
import UIKit
|
|
@preconcurrency import WebKit
|
|
|
|
// MARK: - Settings, Appearance & Pull-to-Refresh
|
|
|
|
extension WebViewController {
|
|
func styleUI() {
|
|
precondition(isViewLoaded && webView != nil)
|
|
|
|
let cachedColors = ThemeColors.cachedThemeColors(for: traitCollection)
|
|
|
|
view.backgroundColor = cachedColors[.primaryBackgroundColor]
|
|
webView?.backgroundColor = cachedColors[.primaryBackgroundColor]
|
|
webView?.scrollView.backgroundColor = cachedColors[.primaryBackgroundColor]
|
|
|
|
// Use the stored reference instead of searching by tag
|
|
if let statusBarView {
|
|
let backgroundColor = server.info.version < .canUseAppThemeForStatusBar
|
|
? cachedColors[.appHeaderBackgroundColor]
|
|
: cachedColors[.appThemeColor]
|
|
statusBarView.backgroundColor = backgroundColor
|
|
statusBarView.isOpaque = true
|
|
}
|
|
|
|
refreshControl.tintColor = cachedColors[.primaryColor]
|
|
|
|
let headerBackgroundIsLight = cachedColors[.appThemeColor].isLight
|
|
underlyingPreferredStatusBarStyle = headerBackgroundIsLight ? .darkContent : .lightContent
|
|
|
|
setNeedsStatusBarAppearanceUpdate()
|
|
}
|
|
|
|
func updateWebViewSettings(reason: WebViewSettingsUpdateReason) {
|
|
Current.Log.info("updating web view settings for \(reason)")
|
|
|
|
// iOS 14's `pageZoom` property is almost this, but not quite - it breaks the layout as well
|
|
// This is quasi-private API that has existed since pre-iOS 10, but the implementation
|
|
// changed in iOS 12 to be like the +/- zoom buttons in Safari, which scale content without
|
|
// resizing the scrolling viewport.
|
|
let viewScale = Current.settingsStore.pageZoom.viewScaleValue
|
|
Current.Log.info("setting view scale to \(viewScale)")
|
|
webView.setValue(viewScale, forKey: "viewScale")
|
|
|
|
if !Current.isCatalyst {
|
|
let zoomValue = Current.settingsStore.pinchToZoom ? "true" : "false"
|
|
webView.evaluateJavaScript("setOverrideZoomEnabled(\(zoomValue))", completionHandler: nil)
|
|
}
|
|
|
|
if reason == .settingChange {
|
|
setNeedsStatusBarAppearanceUpdate()
|
|
setNeedsUpdateOfHomeIndicatorAutoHidden()
|
|
updateEdgeToEdgeLayout()
|
|
}
|
|
}
|
|
|
|
@objc func updateWebViewSettingsForNotification() {
|
|
updateWebViewSettings(reason: .settingChange)
|
|
}
|
|
|
|
func updateEdgeToEdgeLayout() {
|
|
guard let statusBarView else { return }
|
|
|
|
// Edge-to-edge mode only applies to iOS (not Catalyst)
|
|
// Also use edge-to-edge behavior when fullScreen is enabled (status bar hidden)
|
|
let edgeToEdge = (Current.settingsStore.edgeToEdge || Current.settingsStore.fullScreen) && !Current.isCatalyst
|
|
|
|
// Deactivate the current constraint
|
|
webViewTopConstraint?.isActive = false
|
|
|
|
// Create the new constraint based on edge-to-edge setting
|
|
if edgeToEdge {
|
|
webViewTopConstraint = webView.topAnchor.constraint(equalTo: view.topAnchor)
|
|
statusBarView.isHidden = true
|
|
} else {
|
|
webViewTopConstraint = webView.topAnchor.constraint(equalTo: statusBarView.bottomAnchor)
|
|
statusBarView.isHidden = false
|
|
}
|
|
webViewTopConstraint?.isActive = true
|
|
|
|
// Force layout update
|
|
view.setNeedsLayout()
|
|
view.layoutIfNeeded()
|
|
|
|
// Refresh styling to ensure statusBarView has proper background color
|
|
styleUI()
|
|
|
|
// Animate the layout change
|
|
UIView.animate(withDuration: 0.25) {
|
|
self.view.layoutIfNeeded()
|
|
}
|
|
}
|
|
|
|
func setupPullToRefresh() {
|
|
if !Current.isCatalyst {
|
|
// refreshing is handled by menu/keyboard shortcuts
|
|
refreshControl.addTarget(self, action: #selector(pullToRefresh(_:)), for: .valueChanged)
|
|
webView.scrollView.addSubview(refreshControl)
|
|
webView.scrollView.bounces = true
|
|
}
|
|
}
|
|
|
|
@objc func pullToRefresh(_ sender: UIRefreshControl) {
|
|
let now = Current.date()
|
|
|
|
// Check if this is a consecutive pull-to-refresh within 10 seconds
|
|
if let lastTimestamp = lastPullToRefreshTimestamp,
|
|
now.timeIntervalSince(lastTimestamp) < 10 {
|
|
// Second pull-to-refresh within 10 seconds - reset frontend cache
|
|
Current.Log.info("Consecutive pull-to-refresh detected within 10 seconds, resetting frontend cache")
|
|
Current.impactFeedback.impactOccurred(style: .medium)
|
|
|
|
// Reset the cache
|
|
Current.websiteDataStoreHandler.cleanCache { [weak self] in
|
|
Current.Log.info("Frontend cache reset after consecutive pull-to-refresh")
|
|
self?.pullToRefreshActions()
|
|
}
|
|
|
|
// Set the timestamp to now after cache reset to ensure proper timing for next pull
|
|
// This prevents immediate re-triggering while still tracking for future pulls
|
|
lastPullToRefreshTimestamp = now
|
|
} else {
|
|
// First pull-to-refresh or outside the 10-second window
|
|
lastPullToRefreshTimestamp = now
|
|
pullToRefreshActions()
|
|
}
|
|
}
|
|
|
|
func pullToRefreshActions() {
|
|
refresh()
|
|
updateSensors()
|
|
}
|
|
|
|
@objc func updateSensors() {
|
|
// called via menu/keyboard shortcut too
|
|
firstly {
|
|
HomeAssistantAPI.manuallyUpdate(
|
|
applicationState: UIApplication.shared.applicationState,
|
|
type: .userRequested
|
|
)
|
|
}.catch { error in
|
|
Current.Log.error("Error when updating sensors from WKWebView reload: \(error)")
|
|
}
|
|
}
|
|
}
|