Luminate/Sources/LuminateLibrary/SearchView.swift

117 lines
3.2 KiB
Swift

import Foundation
import Adwaita
import LuminateCore
struct SearchView: View {
var client: JellyfinClient
var userId: String
@State private var searchText = ""
@State private var results: [Components.Schemas.SearchHint] = []
@State private var isSearching = false
var view: Body {
VStack {
SearchEntry()
.text($searchText)
.placeholderText("Search")
if isSearching {
Spinner()
.padding(20)
} else {
ScrollView {
VStack {
ForEach(results) { hint in
SearchResultRow(hint: hint, client: client)
}
}
}
}
}
.padding()
}
private func performSearch() {
guard !searchText.isEmpty || searchText == "" else {
results = []
return
}
isSearching = true
Task {
let result = try? await client.getSearchHints(
searchTerm: searchText,
userId: userId,
limit: 50
)
await MainActor.run {
results = result?.searchHints ?? []
isSearching = false
}
}
}
}
extension Components.Schemas.SearchHint: Identifiable {
public var id: String { id ?? itemId ?? String(describing: self) }
}
struct SearchResultRow: View {
var hint: Components.Schemas.SearchHint
var client: JellyfinClient
@State private var imageData: Data?
var view: Body {
HStack {
if let data = imageData {
Picture()
.data(data)
.frame(minWidth: 80, minHeight: 120)
.frame(maxWidth: 80)
.frame(maxHeight: 120)
.style("card")
} else {
Box(spacing: 0) {}
.frame(minWidth: 80, minHeight: 120)
.frame(maxWidth: 80)
.frame(maxHeight: 120)
.style("card")
}
VStack {
Text(hint.name ?? "")
.style("body")
.halign(.start)
if let type = hint._type?.value1 {
Text("\(type)")
.style("caption")
.halign(.start)
}
if let year = hint.productionYear {
Text("\(year)")
.style("caption")
.halign(.start)
}
Text(hint.runtimeString)
.style("caption")
.halign(.start)
}
.hexpand(true)
}
.padding(5, .vertical)
.onAppear {
loadImage()
}
}
private func loadImage() {
guard let tag = hint.primaryImageTag,
let itemId = hint.id ?? hint.itemId else { return }
Task {
guard let url = await client.imageURL(
itemId: itemId, imageType: .primary, tag: tag, maxWidth: 160
) else { return }
let service = ImageService()
imageData = try? await service.loadImage(url: url)
}
}
}