fix view
This commit is contained in:
parent
cac31802b3
commit
22b74a9b36
79
dimensionhub/Views/Search/SearchBar.swift
Normal file
79
dimensionhub/Views/Search/SearchBar.swift
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// SearchBar.swift
|
||||
// dimensionhub
|
||||
//
|
||||
// Created by 安礼成 on 2025/4/8.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// 搜索框
|
||||
struct SearchBar: View {
|
||||
@State private var isSearching = false
|
||||
|
||||
@Binding<String> var searchText: String
|
||||
var placeholder: String
|
||||
var onSearch: () -> Void
|
||||
|
||||
@FocusState private var isFocused
|
||||
|
||||
var body: some View {
|
||||
// 自定义搜索栏
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
// 输入框
|
||||
TextField(placeholder, text: $searchText)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.keyboardType(.default)
|
||||
.focused($isFocused)
|
||||
.submitLabel(.search)
|
||||
.onSubmit {
|
||||
onSearch()
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.padding(8)
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(8)
|
||||
.overlay(alignment: .trailing) {
|
||||
HStack {
|
||||
if isSearching {
|
||||
Button(action: {
|
||||
searchText = ""
|
||||
}) {
|
||||
Image(systemName: "multiply.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
.padding(.trailing, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
// 搜索按钮
|
||||
Button {
|
||||
onSearch()
|
||||
} label: {
|
||||
Text("搜索")
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.padding(.trailing, 10)
|
||||
.disabled(searchText.isEmpty)
|
||||
}
|
||||
.onChange(of: searchText) {
|
||||
if searchText.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
isSearching = false
|
||||
} else {
|
||||
isSearching = true
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.async {
|
||||
isFocused = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
// SearchBar()
|
||||
//}
|
||||
64
dimensionhub/Views/Search/SearchDramaGroupView.swift
Normal file
64
dimensionhub/Views/Search/SearchDramaGroupView.swift
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// SearchDramaGroupView.swift
|
||||
// dimensionhub
|
||||
//
|
||||
// Created by 安礼成 on 2025/4/8.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// 显示分组信息
|
||||
struct SearchDramaGroupView: View {
|
||||
let group: SearchModel.DramaGroup
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: 10) {
|
||||
ForEach(group.items, id: \.id) { item in
|
||||
NavigationLink(destination: DetailView(id: item.id)) {
|
||||
AsyncImage(url: URL(string: item.thumb)) { phase in
|
||||
switch phase {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(height: 180)
|
||||
.clipped()
|
||||
default:
|
||||
Image("ph_img_big")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.clipped()
|
||||
}
|
||||
|
||||
}
|
||||
.frame(width: 370, height: 180)
|
||||
.overlay(alignment: .topLeading) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(item.name)
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(item.status)
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(5)
|
||||
.background(
|
||||
Color.black.opacity(0.6)
|
||||
)
|
||||
.cornerRadius(5)
|
||||
.padding(8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
// SearchDramaGroupView()
|
||||
//}
|
||||
54
dimensionhub/Views/Search/SearchModel.swift
Normal file
54
dimensionhub/Views/Search/SearchModel.swift
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// SearchModel.swift
|
||||
// dimensionhub
|
||||
//
|
||||
// Created by 安礼成 on 2025/4/8.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Observation
|
||||
|
||||
@Observable
|
||||
final class SearchModel {
|
||||
|
||||
var dramaGroups: [DramaGroup] = []
|
||||
|
||||
// 请求的数据类型
|
||||
struct DramaGroup: Codable {
|
||||
struct Item: Codable {
|
||||
let id: Int
|
||||
let name: String
|
||||
let time: Int
|
||||
let thumb: String
|
||||
let status: String
|
||||
}
|
||||
|
||||
let group_id: String
|
||||
let group_name: String
|
||||
let items: [Item]
|
||||
}
|
||||
|
||||
// 搜素功能
|
||||
func search(userId: String, name: String) async {
|
||||
guard let encodeName = name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
|
||||
await MainActor.run {
|
||||
self.dramaGroups = []
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
let response = await API.searchDrama(userId: userId, name: encodeName, as: [DramaGroup].self)
|
||||
switch response {
|
||||
case .result(let dramaGroups):
|
||||
await MainActor.run {
|
||||
self.dramaGroups = dramaGroups
|
||||
}
|
||||
case .error(let int32, let string):
|
||||
print("error_code: \(int32), message: \(string)")
|
||||
await MainActor.run {
|
||||
self.dramaGroups = []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
133
dimensionhub/Views/Search/SearchView.swift
Normal file
133
dimensionhub/Views/Search/SearchView.swift
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// SearchView.swift
|
||||
// dimensionhub
|
||||
//
|
||||
// Created by 安礼成 on 2025/4/1.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct SearchView: View {
|
||||
@Environment(\.modelContext) var modelContext
|
||||
@State var showHistoryNum: Int = 2
|
||||
|
||||
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@State var searchText: String = ""
|
||||
|
||||
@State var searchModel = SearchModel()
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
Button(action: { dismiss() }) {
|
||||
Image(systemName: "chevron.left")
|
||||
.font(.system(size: 20, weight: .medium))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
SearchBar(searchText: $searchText, placeholder: "搜索...") {
|
||||
let trimmedSearchText = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmedSearchText.isEmpty {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
Task.detached {
|
||||
await searchModel.search(userId: userId, name: trimmedSearchText)
|
||||
}
|
||||
|
||||
// let historyModel = SearchHistory(keyword: trimmedSearchText, timestamp: Date())
|
||||
// modelContext.insert(historyModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 50)
|
||||
.padding([.top, .bottom], 8)
|
||||
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
// 基于日期的更新列表
|
||||
LazyVStack(alignment: .center, spacing: 10) {
|
||||
ForEach(searchModel.dramaGroups, id: \.group_id) { group in
|
||||
SearchDramaGroupView(group: group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.navigationTitle("")
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.padding(8)
|
||||
.ignoresSafeArea(edges: .bottom)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SearchView {
|
||||
|
||||
struct SearchHistoryView1: View {
|
||||
@Query(sort: \SearchHistory.timestamp, order: .reverse) private var historyItems: [SearchHistory]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if historyItems.count > 5 {
|
||||
ForEach(Array(0..<5), id: \.self) { idx in
|
||||
SearchHistoryItemView(history: historyItems[idx]) {
|
||||
print("click me")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
//self.showHistoryNum = 5
|
||||
} label: {
|
||||
Text("查看更多历史")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
} else {
|
||||
ForEach(historyItems) { history in
|
||||
SearchHistoryItemView(history: history) {
|
||||
print("click me")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索历史
|
||||
struct SearchHistoryItemView: View {
|
||||
let history: SearchHistory
|
||||
var onClick: () -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 20) {
|
||||
Image("lost_network")
|
||||
.resizable()
|
||||
.clipShape(Circle())
|
||||
.clipped()
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text(history.keyword)
|
||||
.font(.system(size: 16))
|
||||
.lineLimit(1)
|
||||
.frame(width: 280, alignment: .leading)
|
||||
|
||||
Button(action: {
|
||||
onClick()
|
||||
}) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
SearchView()
|
||||
}
|
||||
@ -1,286 +0,0 @@
|
||||
//
|
||||
// SearchView.swift
|
||||
// dimensionhub
|
||||
//
|
||||
// Created by 安礼成 on 2025/4/1.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct SearchView: View {
|
||||
@Environment(\.modelContext) var modelContext
|
||||
@State var showHistoryNum: Int = 2
|
||||
|
||||
@AppStorage("userId") private var userId: String = Utils.defaultUserId()
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@State var searchText: String = ""
|
||||
|
||||
// 请求的数据类型
|
||||
struct DramaGroup: Codable {
|
||||
struct Item: Codable {
|
||||
let id: Int
|
||||
let name: String
|
||||
let time: Int
|
||||
let thumb: String
|
||||
let status: String
|
||||
}
|
||||
|
||||
let group_id: String
|
||||
let group_name: String
|
||||
let items: [Item]
|
||||
}
|
||||
|
||||
@State var dramaGroups: [DramaGroup] = []
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack(alignment: .center, spacing: 0) {
|
||||
Button(action: { dismiss() }) {
|
||||
Image(systemName: "chevron.left")
|
||||
.font(.system(size: 20, weight: .medium))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
SearchBar(searchText: $searchText, placeholder: "搜索...") {
|
||||
let trimmedSearchText = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmedSearchText.isEmpty {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
Task {
|
||||
let dramaGroups = await self.search(userId: userId, name: trimmedSearchText)
|
||||
DispatchQueue.main.async {
|
||||
self.dramaGroups = dramaGroups
|
||||
}
|
||||
}
|
||||
|
||||
// let historyModel = SearchHistory(keyword: trimmedSearchText, timestamp: Date())
|
||||
// modelContext.insert(historyModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: 50)
|
||||
.padding([.top, .bottom], 8)
|
||||
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
// 基于日期的更新列表
|
||||
LazyVStack(alignment: .center, spacing: 10) {
|
||||
ForEach(dramaGroups, id: \.group_id) { group in
|
||||
DramaGroupView(group: group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.navigationTitle("")
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.padding(8)
|
||||
.ignoresSafeArea(edges: .bottom)
|
||||
}
|
||||
|
||||
// 搜素功能
|
||||
func search(userId: String, name: String) async -> [DramaGroup] {
|
||||
guard let encodeName = name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
|
||||
return []
|
||||
}
|
||||
|
||||
let response = await API.searchDrama(userId: userId, name: encodeName, as: [DramaGroup].self)
|
||||
switch response {
|
||||
case .result(let dramaGroups):
|
||||
return dramaGroups
|
||||
case .error(let int32, let string):
|
||||
print("error_code: \(int32), message: \(string)")
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchView {
|
||||
|
||||
// 显示分组信息
|
||||
struct DramaGroupView: View {
|
||||
let group: DramaGroup
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: 10) {
|
||||
ForEach(group.items, id: \.id) { item in
|
||||
NavigationLink(destination: DetailView(id: item.id)) {
|
||||
AsyncImage(url: URL(string: item.thumb)) { phase in
|
||||
switch phase {
|
||||
case .empty:
|
||||
ProgressView()
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(height: 180)
|
||||
.clipped()
|
||||
default:
|
||||
Image("ph_img_big")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.clipped()
|
||||
}
|
||||
|
||||
}
|
||||
.frame(width: 370, height: 180)
|
||||
.overlay(alignment: .topLeading) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(item.name)
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(item.status)
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(5)
|
||||
.background(
|
||||
Color.black.opacity(0.6)
|
||||
)
|
||||
.cornerRadius(5)
|
||||
.padding(8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索框
|
||||
struct SearchBar: View {
|
||||
@State private var isSearching = false
|
||||
|
||||
@Binding<String> var searchText: String
|
||||
var placeholder: String
|
||||
var onSearch: () -> Void
|
||||
|
||||
@FocusState private var isFocused
|
||||
|
||||
var body: some View {
|
||||
// 自定义搜索栏
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
// 输入框
|
||||
TextField(placeholder, text: $searchText)
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.keyboardType(.default)
|
||||
.focused($isFocused)
|
||||
.submitLabel(.search)
|
||||
.onSubmit {
|
||||
onSearch()
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.padding(8)
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(8)
|
||||
.overlay(alignment: .trailing) {
|
||||
HStack {
|
||||
if isSearching {
|
||||
Button(action: {
|
||||
searchText = ""
|
||||
}) {
|
||||
Image(systemName: "multiply.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
.padding(.trailing, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
// 搜索按钮
|
||||
Button {
|
||||
onSearch()
|
||||
} label: {
|
||||
Text("搜索")
|
||||
.font(.system(size: 18))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.padding(.trailing, 10)
|
||||
.disabled(searchText.isEmpty)
|
||||
}
|
||||
.onChange(of: searchText) {
|
||||
if searchText.trimmingCharacters(in: .whitespaces).isEmpty {
|
||||
isSearching = false
|
||||
} else {
|
||||
isSearching = true
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.async {
|
||||
isFocused = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct SearchHistoryView1: View {
|
||||
@Query(sort: \SearchHistory.timestamp, order: .reverse) private var historyItems: [SearchHistory]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
if historyItems.count > 5 {
|
||||
ForEach(Array(0..<5), id: \.self) { idx in
|
||||
SearchHistoryItemView(history: historyItems[idx]) {
|
||||
print("click me")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
//self.showHistoryNum = 5
|
||||
} label: {
|
||||
Text("查看更多历史")
|
||||
.font(.system(size: 16))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
} else {
|
||||
ForEach(historyItems) { history in
|
||||
SearchHistoryItemView(history: history) {
|
||||
print("click me")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索历史
|
||||
struct SearchHistoryItemView: View {
|
||||
let history: SearchHistory
|
||||
var onClick: () -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 20) {
|
||||
Image("lost_network")
|
||||
.resizable()
|
||||
.clipShape(Circle())
|
||||
.clipped()
|
||||
.frame(width: 25, height: 25)
|
||||
|
||||
Text(history.keyword)
|
||||
.font(.system(size: 16))
|
||||
.lineLimit(1)
|
||||
.frame(width: 280, alignment: .leading)
|
||||
|
||||
Button(action: {
|
||||
onClick()
|
||||
}) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 14))
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
SearchView()
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user