iOS/Sources/App/WebView/Views/WebViewEmptyStateView.swift
Bruno Pantaleão Gonçalves 5f9dd2b16c
Increase empty state delay and tweak close buttons on modal presentations (#3805)
<!-- 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. -->

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-10 10:40:23 -03:00

135 lines
4.4 KiB
Swift

import Shared
import SwiftUI
import UIKit
struct WebViewEmptyStateView: View {
@Environment(\.safeAreaInsets) private var safeAreaInsets
@State private var showCloseButton = false
let server: Server
let retryAction: (() -> Void)?
let settingsAction: (() -> Void)?
let dismissAction: (() -> Void)?
var body: some View {
ZStack(alignment: .topTrailing) {
content
header
}
.ignoresSafeArea()
}
private var header: some View {
Group {
serverSelection
ModalCloseButton {
dismissAction?()
}
.frame(maxWidth: .infinity, alignment: .trailing)
}
.padding()
// This is needed alongside with the ignores safe area below because
// this view is added as a subview to the WebView
.offset(x: 0, y: safeAreaInsets.top)
}
private var content: some View {
VStack(spacing: DesignSystem.Spaces.two) {
Image(.logo)
.resizable()
.scaledToFit()
.frame(width: 80, height: 80)
.foregroundColor(.accentColor)
Text(L10n.WebView.EmptyState.title)
.font(.title2)
.fontWeight(.semibold)
Text(L10n.WebView.EmptyState.body)
.font(.callout)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal, DesignSystem.Spaces.two)
VStack(spacing: DesignSystem.Spaces.one) {
Button(action: {
retryAction?()
}) {
Text(L10n.WebView.EmptyState.retryButton)
}
.buttonStyle(.primaryButton)
Button(action: {
settingsAction?()
}) {
Text(L10n.WebView.EmptyState.openSettingsButton)
}
.buttonStyle(.secondaryButton)
}
.frame(maxWidth: Sizes.maxWidthForLargerScreens)
.padding(.horizontal, DesignSystem.Spaces.two)
.padding(.top)
}
.padding(DesignSystem.Spaces.three)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(uiColor: .systemBackground))
}
@ViewBuilder
private var serverSelection: some View {
if Current.servers.all.count > 1 {
HStack {
Spacer()
ServerPickerView(server: server)
#if targetEnvironment(macCatalyst)
.padding()
#endif
// Using .secondarySystemBackground to visually distinguish the server selection view
.background(Color(uiColor: .secondarySystemBackground))
.clipShape(Capsule())
Spacer()
}
}
}
}
#Preview {
WebViewEmptyStateView(server: ServerFixture.standard) {} settingsAction: {} dismissAction: {}
}
final class WebViewEmptyStateWrapperView: UIView {
private let hostingController: UIHostingController<WebViewEmptyStateView>
private let server: Server
init(
server: Server,
retryAction: (() -> Void)? = nil,
settingsAction: (() -> Void)? = nil,
dismissAction: (() -> Void)? = nil
) {
self.server = server
let swiftUIView = WebViewEmptyStateView(
server: server,
retryAction: retryAction,
settingsAction: settingsAction,
dismissAction: dismissAction
)
self.hostingController = UIHostingController(rootView: swiftUIView)
super.init(frame: .zero)
setup()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: trailingAnchor),
])
backgroundColor = .clear
}
}