import SwiftUI import WaterfallGrid struct PostGridView: View { @EnvironmentObject var settings: SettingsManager @EnvironmentObject var manager: BooruManager @State private var isSearchHistoryPresented = false @Binding var selectedTab: Int @Environment(\.isSearching) private var isSearching var filteredPosts: [BooruPost] { manager.posts .filter { settings.displayRatings.contains($0.rating) } } var body: some View { ScrollViewReader { _ in ScrollView { if filteredPosts.isEmpty { ProgressView() .padding() } WaterfallGrid(filteredPosts, id: \.id) { post in waterfallGridContent(post: post) } .gridStyle(columns: settings.thumbnailGridColumns) .padding(8) } .searchable(text: $manager.searchText, prompt: "Tags") .searchSuggestions { if settings.searchSuggestionsMode != .disabled { SearchSuggestionsView( items: searchSuggestionsItems(), searchText: $manager.searchText ) } } .onSubmit(of: .search) { manager.performSearch(settings: settings) } .navigationDestination(for: BooruPost.self) { post in PostDetailsView(post: post) } .onChange(of: manager.searchText) { _, _ in if manager.searchText.isEmpty, !isSearching { Task { manager.performSearch() } } } .toolbar { #if os(macOS) ToolbarItem { Button(action: { Task { await manager.fetchPosts(page: 1, tags: manager.tags, replace: true) } }) { Label("Refresh", systemImage: "arrow.clockwise") } .disabled(manager.isLoading) } #endif #if os(macOS) ToolbarItem { Button(action: { Task { manager.loadNextPage() } }) { Label("Manually Load Next Page", systemImage: "arrow.triangle.2.circlepath") } .disabled(manager.isLoading) } #else ToolbarItem(placement: .bottomBar) { Button(action: { Task { manager.loadNextPage() } }) { Label("Manually Load Next Page", systemImage: "arrow.triangle.2.circlepath") } .disabled(manager.isLoading) } ToolbarItem(placement: .bottomBar) { Button(action: { Task { isSearchHistoryPresented.toggle() } }) { Label("Search History", systemImage: "clock.arrow.circlepath") } } if manager.isLoading { ToolbarItem { ProgressView() } } #endif if !manager.tags.isEmpty { #if os(macOS) ToolbarItem { PostGridBookmarkButtonView() } #else ToolbarItem(placement: .bottomBar) { PostGridBookmarkButtonView() } #endif } } .navigationTitle("Posts") .refreshable { await manager.fetchPosts(page: 1, tags: manager.tags, replace: true) } .scrollDisabled(manager.isLoading) .sheet(isPresented: $isSearchHistoryPresented) { PostGridSearchHistoryView( selectedTab: $selectedTab, isPresented: $isSearchHistoryPresented ) .frame(minHeight: 250) } } } private func waterfallGridContent(post: BooruPost) -> some View { Button { manager.selectedPost = post } label: { PostGridThumbnailView(post: post, posts: filteredPosts) } .buttonStyle(PlainButtonStyle()) .contextMenu { Button(action: { manager.selectedPost = post }) { Label("Select Post", systemImage: "arrow.right.circle") } } } private func searchSuggestionsItems() -> [Either] { let items: [Either] switch settings.searchSuggestionsMode { case .tags: items = manager.allTags .map { Either.left($0) } case .history: items = settings.searchHistory .map { Either.right($0) } case .disabled: items = [] } return items } }