import SwiftUI struct GenericListView: View { @EnvironmentObject private var settings: SettingsManager @ObservedObject var manager: BooruManager @Binding var selectedTab: Int @State private var searchText: String = "" @State private var isShowingRemoveAllConfirmation = false @Binding var isPresented: Bool let title: String let emptyMessage: String let emptyIcon: String let emptyDescription: String let removeAllMessage: String let removeAllButtonText: String let items: [T] let removeAction: (IndexSet) -> Void let removeActionUUID: (UUID) -> Void let removeAllAction: () -> Void var filteredItems: [T] { guard !searchText.isEmpty else { return items } return items.filter { item in item.tags .joined(separator: " ") .lowercased() .contains(searchText.lowercased()) } } var body: some View { NavigationStack { VStack { if items.isEmpty { ContentUnavailableView( emptyMessage, systemImage: emptyIcon, description: Text(emptyDescription) ) } else { List { if filteredItems.isEmpty, !searchText.isEmpty { Text("No matching items found") } ForEach( filteredItems.sorted { $0.date > $1.date }, id: \.id ) { item in itemButtonContent(item: item) } .onDelete(perform: removeAction) } } } } .navigationTitle(title) .searchable(text: $searchText) .toolbar { ToolbarItem { Button(action: { isShowingRemoveAllConfirmation = true }) { Label("Remove All", systemImage: "trash") } } } .confirmationDialog( removeAllMessage, isPresented: $isShowingRemoveAllConfirmation ) { Button(removeAllButtonText) { removeAllAction() } } } func itemButtonContent(item: T) -> some View { Button(action: { let previousProvider = settings.preferredBooru settings.preferredBooru = item.provider manager.searchText = item.tags.joined(separator: " ") selectedTab = 0 if previousProvider == settings.preferredBooru { manager.performSearch(settings: settings) } isPresented.toggle() }) { GenericItemView( item: item, removeAction: removeActionUUID ) } .contextMenu { Button(action: { manager.searchText += " \(item.tags.joined(separator: " "))" manager.selectedPost = nil manager.performSearch(settings: settings) isPresented.toggle() }) { Label("Add to Search", systemImage: "plus") } Button(action: { settings.addBookmark(provider: settings.preferredBooru, tags: item.tags) }) { Label("Bookmark Tag\(item.tags.count == 1 ? "" : "s")", systemImage: "bookmark") } } #if os(macOS) .buttonStyle(.plain) #endif } }