import SwiftUI enum FileFilterType: String, Hashable, CaseIterable, Identifiable { case images case text case videos case other var text: String { switch self { case .images: return "Image" case .text: return "Text" case .videos: return "Video" case .other: return "Other" } } var id: String { rawValue } func matches(_ type: FileType) -> Bool { switch self { case .images: return type.isImage case .text: return type.isTextFile case .videos: return type.isVideo case .other: return type.isOtherFile } } } struct FileListView: View { @EnvironmentObject private var content: Content @Binding var selectedFile: FileResource? @State private var selectedFileType: FileFilterType @State private var searchString = "" let allowedType: FileFilterType? init(selectedFile: Binding, allowedType: FileFilterType? = nil) { self._selectedFile = selectedFile self.allowedType = allowedType self.selectedFileType = allowedType ?? .images } var filesBySelectedType: [FileResource] { content.files.filter { selectedFileType.matches($0.type) } } var filteredFiles: [FileResource] { guard !searchString.isEmpty else { return filesBySelectedType } return filesBySelectedType.filter { $0.id.contains(searchString) } } var body: some View { VStack(alignment: .center) { Picker("", selection: $selectedFileType) { ForEach(FileFilterType.allCases) { type in Text(type.text).tag(type) } } .pickerStyle(.segmented) .padding(.trailing, 7) .disabled(allowedType != nil) TextField("", text: $searchString, prompt: Text("Search")) .textFieldStyle(.roundedBorder) .padding(.horizontal, 8) List(filteredFiles, selection: $selectedFile) { file in Text(file.id).tag(file) } .onChange(of: selectedFileType) { oldValue, newValue in guard oldValue != newValue else { return } let newFile = filteredFiles.first guard let selectedFile else { if let newFile { DispatchQueue.main.async { selectedFile = newFile } } return } if newValue.matches(selectedFile.type) { return } DispatchQueue.main.async { self.selectedFile = newFile } } } .onAppear { if selectedFile == nil { DispatchQueue.main.async { selectedFile = content.files.first } } } } } #Preview { NavigationSplitView { FileListView(selectedFile: .constant(nil)) .environmentObject(Content.mock) .navigationSplitViewColumnWidth(250) } detail: { Text("") .frame(width: 50) } }