import SwiftUI struct PostDetailsCarouselView: View { @EnvironmentObject var manager: BooruManager @EnvironmentObject var settings: SettingsManager let posts: [BooruPost] let focusedPost: BooruPost? @Binding var loadingStage: BooruPostLoadingState @State private var currentIndex: Int private let cacheManager = ImageCacheManager.shared init( posts: [BooruPost], loadingStage: Binding, focusedPost: BooruPost? = nil ) { self.posts = posts self.focusedPost = focusedPost _loadingStage = loadingStage if let focused = focusedPost, let index = posts.firstIndex(where: { $0.id == focused.id }) { self._currentIndex = State(initialValue: index) } else { self._currentIndex = State(initialValue: 0) } } func imageURL(post: BooruPost) -> URL? { switch settings.detailViewQuality { case .preview: post.previewURL case .sample: post.sampleURL case .original: post.fileURL } } var body: some View { TabView(selection: $currentIndex) { ForEach(Array(posts.enumerated()), id: \.offset) { index, post in PostDetailsCarouselItemView( post: post, index: index, loadingStage: $loadingStage, imageURL: imageURL ) } } .onChange(of: currentIndex) { if currentIndex == posts.count - 1 { manager.loadNextPage() } manager.selectedPost = posts[currentIndex] preloadNearbyImages() } .onAppear(perform: preloadNearbyImages) #if !os(macOS) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) #endif } private func preloadNearbyImages() { let preloadRange = settings.preloadedCarouselImages guard preloadRange > 0 else { return } let startIndex = max(0, currentIndex - preloadRange) let endIndex = min(posts.count - 1, currentIndex + preloadRange) var urlsToPreload: [URL] = [] for index in startIndex...endIndex { if let url = imageURL(post: posts[index]) { urlsToPreload.append(url) } urlsToPreload.append(posts[index].previewURL) } cacheManager.preloadImages(urlsToPreload) } }