Files
iOS/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift
Bruno Pantaleão Gonçalves 7cbdcb762f Remove legacy actions (#4584)
<!-- 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-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-04 15:20:24 +02:00

219 lines
7.1 KiB
Swift

import SFSafeSymbols
import Shared
import SwiftUI
struct MagicItemAddView: View {
enum Context {
case watch
case carPlay
case widget
case appIconShortcut
}
enum PickerOption {
case entities
case scripts
case scenes
case assistPipelines
}
@Environment(\.dismiss) private var dismiss
@StateObject private var viewModel = MagicItemAddViewModel()
@State private var selectedEntity: HAAppEntity?
private let visiblePickerOptions: [PickerOption]
private let initialItemType: MagicItemAddType
let context: Context
let itemToAdd: (MagicItem?) -> Void
init(
context: Context,
initialItemType: MagicItemAddType? = nil,
visiblePickerOptions: [PickerOption]? = nil,
itemToAdd: @escaping (MagicItem?) -> Void
) {
self.context = context
self.itemToAdd = itemToAdd
let resolvedPickerOptions = visiblePickerOptions ?? {
var options: [PickerOption] = []
if [.carPlay, .widget, .appIconShortcut].contains(context) {
options.append(.entities)
}
if context != .widget {
// In other context user can just select entities directly
// In Apple watch we don't have entity support yet
if context == .watch {
options.append(.scripts)
options.append(.scenes)
}
}
if [.carPlay, .appIconShortcut].contains(context), #available(iOS 26.0, *) {
options.append(.assistPipelines)
}
return options
}()
self.visiblePickerOptions = resolvedPickerOptions
self.initialItemType = initialItemType ?? Self.defaultItemType(
for: context,
visiblePickerOptions: resolvedPickerOptions
)
}
var body: some View {
NavigationView {
Group {
switch viewModel.selectedItemType {
case .entities:
VStack {
pickerView
.padding(.horizontal)
entitiesPerServerList()
}
case .scripts:
VStack {
pickerView
.padding(.horizontal)
entitiesPerServerList(domainFilter: .script)
}
case .scenes:
VStack {
pickerView
.padding(.horizontal)
entitiesPerServerList(domainFilter: .scene)
}
case .assistPipelines:
VStack {
pickerView
.padding(.horizontal)
AssistPipelineAddList { pipeline in
itemToAdd(pipeline)
dismiss()
}
}
}
}
.onAppear {
autoSelectItemType()
if viewModel.selectedServerId == nil {
viewModel.selectedServerId = Current.servers.all.first?.identifier.rawValue
}
}
#if targetEnvironment(macCatalyst)
.toolbar(content: {
CloseButton {
dismiss()
}
})
#endif
}
.navigationViewStyle(.stack)
.modify { view in
if #available(iOS 16.0, *) {
view
.presentationDetents([.large])
.presentationDragIndicator(.visible)
} else {
view
}
}
}
@ViewBuilder
private var pickerView: some View {
// If there is only one option, don't show the picker
if visiblePickerOptions.count > 1 {
Picker(L10n.MagicItem.ItemType.Selection.List.title, selection: $viewModel.selectedItemType) {
ForEach(visiblePickerOptions, id: \.self) { option in
switch option {
case .entities:
Text(verbatim: L10n.MagicItem.ItemType.Entity.List.title)
.tag(MagicItemAddType.entities)
case .scripts:
Text(verbatim: L10n.MagicItem.ItemType.Script.List.title)
.tag(MagicItemAddType.scripts)
case .scenes:
Text(verbatim: L10n.MagicItem.ItemType.Scene.List.title)
.tag(MagicItemAddType.scenes)
case .assistPipelines:
Text(verbatim: L10n.Widgets.Action.Name.assist)
.tag(MagicItemAddType.assistPipelines)
}
}
}
.pickerStyle(.segmented)
.listRowBackground(Color.clear)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.padding(.top)
}
}
private func autoSelectItemType() {
viewModel.selectedItemType = initialItemType
}
private static func defaultItemType(
for context: Context,
visiblePickerOptions: [PickerOption]
) -> MagicItemAddType {
if let firstOption = visiblePickerOptions.first {
switch firstOption {
case .entities:
return .entities
case .scripts:
return .scripts
case .scenes:
return .scenes
case .assistPipelines:
return .assistPipelines
}
}
switch context {
case .watch:
return .scripts
case .carPlay, .widget, .appIconShortcut:
return .entities
}
}
@ViewBuilder
private func entitiesPerServerList(domainFilter: Domain? = nil) -> some View {
EntityPicker(
selectedServerId: Current.servers.all
.first(where: { $0.identifier.rawValue == viewModel.selectedServerId })?.identifier.rawValue,
selectedEntity: $selectedEntity,
domainFilter: domainFilter,
mode: .inline
)
.background(
NavigationLink("", isActive: .init(get: {
selectedEntity != nil
}, set: { _ in
selectedEntity = nil
})) {
if let selectedEntity {
MagicItemCustomizationView(
mode: .add,
context: context,
item: .init(
id: selectedEntity.entityId,
serverId: selectedEntity.serverId,
type: .entity
)
) { itemToAdd in
self.itemToAdd(itemToAdd)
dismiss()
}
}
}
)
}
}
#Preview {
MagicItemAddView(context: .carPlay) { _ in
}
}