init: init proj
This commit is contained in:
160
DDYSClient/Views/Home/HomeView.swift
Normal file
160
DDYSClient/Views/Home/HomeView.swift
Normal file
@@ -0,0 +1,160 @@
|
||||
import SwiftUI
|
||||
|
||||
struct HomeView: View {
|
||||
var viewModel: HomeViewModel
|
||||
@State private var searchText = ""
|
||||
@State private var searchViewModel = SearchViewModel()
|
||||
|
||||
private var showingSearchResults: Bool {
|
||||
searchViewModel.hasSearched
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if !viewModel.hasData && viewModel.error == nil && !showingSearchResults {
|
||||
ProgressView()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else if showingSearchResults && searchViewModel.isSearching {
|
||||
ProgressView()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} else {
|
||||
ScrollView {
|
||||
if showingSearchResults {
|
||||
searchContent
|
||||
} else {
|
||||
homeContent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("低端影视")
|
||||
.navigationDestination(for: ContentItem.self) { item in
|
||||
DetailView(item: item)
|
||||
}
|
||||
.searchable(text: $searchText, prompt: "搜索电影、电视剧...")
|
||||
.onSubmit(of: .search) {
|
||||
let trimmed = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return }
|
||||
Task {
|
||||
searchViewModel.query = trimmed
|
||||
await searchViewModel.search()
|
||||
}
|
||||
}
|
||||
.onChange(of: searchText) { _, newValue in
|
||||
if newValue.isEmpty {
|
||||
searchViewModel.clear()
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
if showingSearchResults {
|
||||
await searchViewModel.search()
|
||||
} else {
|
||||
await viewModel.loadHome()
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await viewModel.loadHomeIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 首页内容
|
||||
|
||||
@ViewBuilder
|
||||
private var homeContent: some View {
|
||||
if let error = viewModel.error {
|
||||
errorView(error)
|
||||
} else {
|
||||
LazyVStack(alignment: .leading, spacing: 24) {
|
||||
if !viewModel.recommendedItems.isEmpty {
|
||||
sectionHeader("热门推荐")
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack(spacing: 12) {
|
||||
ForEach(viewModel.recommendedItems) { item in
|
||||
NavigationLink(value: item) {
|
||||
ContentCardView(item: item)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
if !viewModel.latestItems.isEmpty {
|
||||
sectionHeader("最新更新")
|
||||
ContentGridView(items: viewModel.latestItems)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 搜索结果
|
||||
|
||||
@ViewBuilder
|
||||
private var searchContent: some View {
|
||||
if let error = searchViewModel.error {
|
||||
VStack(spacing: 16) {
|
||||
Image(systemName: "exclamationmark.triangle")
|
||||
.font(.system(size: 48))
|
||||
.foregroundStyle(.secondary)
|
||||
Text(error)
|
||||
.foregroundStyle(.secondary)
|
||||
Button("重试") {
|
||||
Task { await searchViewModel.search() }
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 300)
|
||||
} else if searchViewModel.results.isEmpty {
|
||||
VStack(spacing: 12) {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.font(.system(size: 48))
|
||||
.foregroundStyle(.secondary)
|
||||
Text("未找到「\(searchViewModel.query)」的相关内容")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 300)
|
||||
} else {
|
||||
LazyVStack(alignment: .leading, spacing: 16) {
|
||||
Text("搜索结果")
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.padding(.horizontal)
|
||||
|
||||
ContentGridView(items: searchViewModel.results) {
|
||||
Task { await searchViewModel.loadMore() }
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
if searchViewModel.isLoadingMore {
|
||||
ProgressView()
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
|
||||
private func sectionHeader(_ title: String) -> some View {
|
||||
Text(title)
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
||||
private func errorView(_ message: String) -> some View {
|
||||
VStack(spacing: 16) {
|
||||
Image(systemName: "exclamationmark.triangle")
|
||||
.font(.system(size: 48))
|
||||
.foregroundStyle(.secondary)
|
||||
Text(message)
|
||||
.foregroundStyle(.secondary)
|
||||
Button("重试") {
|
||||
Task { await viewModel.loadHome() }
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 300)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user