Files
JetsonMediaIOS/Jetson Media/ui/SearchView.swift
2025-08-17 22:08:25 +08:00

197 lines
7.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
import Foundation
//
class SearchHistoryManager {
static let shared = SearchHistoryManager()
private let userDefaultsKey = "search_history"
private let maxHistoryCount = 50
var history: [String] {
UserDefaults.standard.array(forKey: userDefaultsKey) as? [String] ?? []
}
func addHistory(_ query: String) {
var newHistory = history
if let index = newHistory.firstIndex(of: query) {
newHistory.remove(at: index)
}
newHistory.insert(query, at: 0)
if newHistory.count > maxHistoryCount {
newHistory = Array(newHistory.prefix(maxHistoryCount))
}
UserDefaults.standard.set(newHistory, forKey: userDefaultsKey)
}
func removeHistory(_ query: String) {
var newHistory = history
if let index = newHistory.firstIndex(of: query) {
newHistory.remove(at: index)
UserDefaults.standard.set(newHistory, forKey: userDefaultsKey)
}
}
func clearAllHistory() {
UserDefaults.standard.removeObject(forKey: userDefaultsKey)
}
}
//
struct SearchView: View {
@State private var searchQuery: String = ""
@State private var searchResults: [AlbumItem] = []
@State private var isSearching: Bool = false
@State private var showAlert: Bool = false
@State private var alertMessage: String = ""
@State private var searchHistory: [String] = []
var body: some View {
NavigationStack {
Form {
Section(header: Text("Jetson Media")) {
HStack {
TextField("输入搜索内容", text: $searchQuery)
.textFieldStyle(RoundedBorderTextFieldStyle())
.onChange(of: searchQuery) {
if $0.isEmpty {
loadHistory()
}
}
Button(action: performSearch) {
if isSearching {
ProgressView()
} else {
Image(systemName: "magnifyingglass")
}
}
.disabled(searchQuery.isEmpty || isSearching)
}
}
//
if searchQuery.isEmpty && !searchHistory.isEmpty {
Section(header: HStack {
Text("搜索历史")
Spacer()
Button("清除全部") {
SearchHistoryManager.shared.clearAllHistory()
loadHistory()
}
.foregroundColor(.red)
.font(.subheadline)
}) {
ForEach(searchHistory, id: \.self) { query in
// HStack
HStack {
//
Text(query)
.foregroundColor(.primary)
.frame(maxWidth: .infinity, alignment: .leading)
.onTapGesture {
//
searchQuery = query
performSearch()
}
//
Button(action: {
SearchHistoryManager.shared.removeHistory(query)
loadHistory()
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.gray)
}
.buttonStyle(PlainButtonStyle()) //
}
}
}
}
//
if !searchResults.isEmpty {
Section(header: Text("搜索结果")) {
ForEach(searchResults, id: \.album_id) { item in
NavigationLink(destination: PhotoView(albumId: item.album_id)) {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text("ID: \(item.album_id)")
.font(.subheadline)
.foregroundColor(.gray)
}
}
}
}
}
}
.navigationTitle("搜索")
.onAppear {
loadHistory()
}
}
.alert(isPresented: $showAlert) {
Alert(title: Text("提示"), message: Text(alertMessage), dismissButton: .default(Text("确定")))
}
}
private func loadHistory() {
searchHistory = SearchHistoryManager.shared.history
}
private func performSearch() {
guard !searchQuery.isEmpty else { return }
SearchHistoryManager.shared.addHistory(searchQuery)
loadHistory()
isSearching = true
searchResults = []
let encodedQuery = searchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? searchQuery
let urlString = Config.shared.apiURL(
path: "\(Config.Path.search)?search_query=\(encodedQuery)&page=1"
)
guard let url = URL(string: urlString) else {
showAlert(message: "无效的URL")
isSearching = false
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
DispatchQueue.main.async {
self.isSearching = false
if let error = error {
self.showAlert(message: "搜索失败: \(error.localizedDescription)")
return
}
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
self.showAlert(message: "服务器返回错误")
return
}
guard let data = data else {
self.showAlert(message: "没有接收到数据")
return
}
do {
let decoder = JSONDecoder()
self.searchResults = try decoder.decode([AlbumItem].self, from: data)
} catch {
print("解码错误: \(error)")
self.showAlert(message: "解析数据失败: \(error.localizedDescription)")
}
}
}
task.resume()
}
private func showAlert(message: String) {
alertMessage = message
showAlert = true
}
}