mirror of
https://github.com/home-assistant/iOS.git
synced 2026-02-09 00:55:52 -06:00
<!-- 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="1658" height="1142" alt="CleanShot 2026-01-30 at 11 00 58@2x" src="https://github.com/user-attachments/assets/a06062c9-f373-499e-b42a-1b07b244019c" /> ## 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. -->
82 lines
2.8 KiB
Swift
82 lines
2.8 KiB
Swift
import SFSafeSymbols
|
|
import Shared
|
|
import SwiftUI
|
|
|
|
struct EntityRowView: View {
|
|
// This avoids lag while loading a screen with several rows
|
|
@State private var showIcon = false
|
|
@State private var subtitle = ""
|
|
@State private var title = ""
|
|
@State private var icon: UIImage?
|
|
private let entity: HAAppEntity?
|
|
private let optionalTitle: String?
|
|
private let accessoryImageSystemSymbol: SFSymbol?
|
|
private let isSelected: Bool
|
|
|
|
private let iconSize: CGSize = .init(width: 24, height: 24)
|
|
|
|
init(
|
|
entity: HAAppEntity? = nil,
|
|
optionalTitle: String? = nil,
|
|
accessoryImageSystemSymbol: SFSymbol? = nil,
|
|
isSelected: Bool = false
|
|
) {
|
|
self.entity = entity
|
|
self.optionalTitle = optionalTitle
|
|
self.accessoryImageSystemSymbol = accessoryImageSystemSymbol
|
|
self.isSelected = isSelected
|
|
}
|
|
|
|
var body: some View {
|
|
HStack(spacing: DesignSystem.Spaces.two) {
|
|
HStack {
|
|
if showIcon, let icon {
|
|
Image(uiImage: icon)
|
|
}
|
|
}
|
|
.frame(width: iconSize.width, height: iconSize.height)
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(title)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
if !subtitle.isEmpty {
|
|
Text(subtitle)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.font(.footnote)
|
|
.foregroundStyle(Color.secondary)
|
|
}
|
|
}
|
|
if isSelected {
|
|
Image(systemSymbol: .checkmark)
|
|
.foregroundStyle(.haPrimary)
|
|
} else if let accessoryImageSystemSymbol {
|
|
Image(systemSymbol: accessoryImageSystemSymbol)
|
|
.foregroundStyle(.white, .green)
|
|
.font(.title3)
|
|
}
|
|
}
|
|
.animation(.easeInOut, value: showIcon)
|
|
.onAppear {
|
|
title = optionalTitle ?? entity?.registryTitle ?? entity?.name ?? ""
|
|
subtitle = (entity?.contextualSubtitle).orEmpty
|
|
let fallbackIcon = Domain(entityId: (entity?.entityId).orEmpty)?.icon(deviceClass: entity?.rawDeviceClass)
|
|
if let entity {
|
|
icon = MaterialDesignIcons(
|
|
serversideValueNamed: entity.icon.orEmpty,
|
|
fallback: fallbackIcon ?? .dotsGridIcon
|
|
).image(
|
|
ofSize: .init(width: iconSize.width, height: iconSize.height),
|
|
color: UIColor(Color.gray)
|
|
)
|
|
}
|
|
showIcon = true
|
|
}
|
|
.onDisappear {
|
|
showIcon = false
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
EntityRowView(optionalTitle: "Example Entity")
|
|
}
|