- DetailViewModel 添加 @MainActor 确保状态更新在主线程 - DetailView 消除空白初始状态,ProgressView 作为默认兜底 - 取消时保留加载状态避免页面闪回空白 - 使用 .task(id:) 确保切换条目时任务重新触发 - 海报优先从 JSON-LD image 字段获取,HTML fallback 改用正确选择器 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
1.9 KiB
Swift
66 lines
1.9 KiB
Swift
import Foundation
|
||
|
||
@Observable @MainActor
|
||
final class DetailViewModel {
|
||
var detail: ContentDetail?
|
||
var selectedSourceIndex = 0
|
||
var selectedEpisodeIndex = 0
|
||
var isLoading = false
|
||
var error: String?
|
||
|
||
var currentSource: StreamSource? {
|
||
guard let detail, selectedSourceIndex < detail.sources.count else { return nil }
|
||
return detail.sources[selectedSourceIndex]
|
||
}
|
||
|
||
var currentEpisode: Episode? {
|
||
guard let source = currentSource,
|
||
selectedEpisodeIndex < source.episodes.count else { return nil }
|
||
return source.episodes[selectedEpisodeIndex]
|
||
}
|
||
|
||
var hasMultipleEpisodes: Bool {
|
||
guard let source = currentSource else { return false }
|
||
return source.episodes.count > 1
|
||
}
|
||
|
||
func loadDetail(path: String) async {
|
||
isLoading = true
|
||
error = nil
|
||
|
||
do {
|
||
let html = try await APIClient.shared.fetchDetailPage(path: path)
|
||
let parsedDetail = try HTMLParser.parseContentDetail(html: html)
|
||
self.detail = parsedDetail
|
||
self.selectedSourceIndex = 0
|
||
self.selectedEpisodeIndex = 0
|
||
} catch is CancellationError {
|
||
// 被取消时不清除 loading 状态,让视图继续显示加载中
|
||
return
|
||
} catch let error as URLError where error.code == .cancelled {
|
||
return
|
||
} catch {
|
||
self.error = error.localizedDescription
|
||
}
|
||
isLoading = false
|
||
}
|
||
|
||
func selectSource(_ index: Int) {
|
||
selectedSourceIndex = index
|
||
selectedEpisodeIndex = 0
|
||
}
|
||
|
||
func selectEpisode(_ index: Int) {
|
||
selectedEpisodeIndex = index
|
||
}
|
||
|
||
func nextEpisode() -> Bool {
|
||
guard let source = currentSource else { return false }
|
||
if selectedEpisodeIndex + 1 < source.episodes.count {
|
||
selectedEpisodeIndex += 1
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
}
|