import SwiftUI struct MultiFileSelectionView: View { @Environment(\.dismiss) private var dismiss @EnvironmentObject private var content: Content @Binding private var selectedFiles: [FileResource] let allowedType: FileTypeCategory? let insertSorted: Bool @State private var selectedFileType: FileTypeCategory? @State private var searchString = "" @State private var newSelection: [FileResource] init(selectedFiles: Binding<[FileResource]>, allowedType: FileTypeCategory? = nil, insertSorted: Bool = false) { self._selectedFiles = selectedFiles self.newSelection = selectedFiles.wrappedValue self.allowedType = allowedType self.selectedFileType = allowedType ?? .image self.insertSorted = insertSorted } private var filesBySelectedType: [FileResource] { guard let selectedFileType else { return content.files } return content.files.filter { selectedFileType == $0.type.category } } private var filteredFiles: [FileResource] { guard !searchString.isEmpty else { return filesBySelectedType } return filesBySelectedType.filter { $0.id.contains(searchString) } } var body: some View { GeometryReader { geo in HStack { VStack { Text("Selected files") .font(.title) List { ForEach(newSelection) { file in HStack { Image(systemSymbol: .minusCircleFill) .foregroundStyle(.red) .contentShape(Rectangle()) .onTapGesture { deselect(file: file) } Text(file.id) Spacer() } } .onMove(perform: moveSelectedFile) } HStack { Button("Cancel") { DispatchQueue.main.async { dismiss() } } Button("Save") { selectedFiles = newSelection dismiss() } } }.frame(width: geo.size.width / 2) VStack { Picker("", selection: $selectedFileType) { let all: FileTypeCategory? = nil Text("All").tag(all) ForEach(FileTypeCategory.allCases) { type in Text(type.text).tag(type) } } .padding(.trailing, 7) .disabled(allowedType != nil) TextField("", text: $searchString, prompt: Text("Search")) .textFieldStyle(.roundedBorder) .padding(.horizontal, 8) List(filteredFiles) { file in HStack { if newSelection.contains(file) { Image(systemSymbol: .checkmarkCircleFill) .foregroundStyle(.gray) } else { Image(systemSymbol: .plusCircleFill) .foregroundStyle(.green) } Text(file.id) Spacer() } .contentShape(Rectangle()) .onTapGesture { select(file: file) } } }.frame(width: geo.size.width / 2) } .frame(minHeight: 500, idealHeight: 600) } .frame(minHeight: 500, idealHeight: 600) .padding() } private func deselect(file: FileResource) { guard let index = newSelection.firstIndex(of: file) else { return } newSelection.remove(at: index) } private func select(file: FileResource) { guard !newSelection.contains(file) else { return } guard insertSorted else { newSelection.append(file) return } newSelection.insertSorted(file) } private func moveSelectedFile(from source: IndexSet, to destination: Int) { newSelection.move(fromOffsets: source, toOffset: destination) } }