import Adwaita import LuminateCore public struct HomeView: View { @Injected(\.client) var client @Injected(\.userId) var userId @State private var resumeItems: [Components.Schemas.BaseItemDto] = [] @State private var nextUpItems: [Components.Schemas.BaseItemDto] = [] @State private var latestItems: [Components.Schemas.BaseItemDto] = [] @State private var libraries: [Components.Schemas.BaseItemDto] = [] @State private var isLoading = true @State private var isLoadingData = false public var view: Body { ScrollView { Clamp() .maximumSize(1550) .tighteningThreshold(550) .child { VStack { if isLoading { Spinner() .halign(.center) .valign(.center) .frame(minWidth: 64) .frame(maxWidth: 64) } else { if !resumeItems.isEmpty { MediaRow( title: "Continue Watching", items: resumeItems ) .padding(16, .bottom) } if !nextUpItems.isEmpty { MediaRow( title: "Next Up", items: nextUpItems ) .padding(16, .bottom) } if !latestItems.isEmpty { MediaRow( title: "Recently Added", items: latestItems, onSeeAll: {} ) .padding(16, .bottom) } LibraryGrid( libraries: libraries ) } } .padding(8, .horizontal) } } .hscrollbarPolicy(.never) .propagateNaturalHeight() .onAppear { loadHomeData() } } private func loadHomeData() { Task { async let resume = client.getItems( userId: userId, filters: [.isResumable], sortBy: [.datePlayed], sortOrder: [.descending], limit: 20, recursive: true ) async let nextUp = client.getNextUp(userId: userId, limit: 20) async let latest = client.getLatestMedia(userId: userId, limit: 20) async let views = client.getUserViews(userId: userId) do { let (r, n, l, v) = try await (resume, nextUp, latest, views) resumeItems = r.items ?? [] nextUpItems = n.items ?? [] latestItems = l libraries = v.items ?? [] isLoading = false } catch { isLoading = false } isLoadingData = false } } }