From a6206b68818d9e0c1d0a5e7f7d1c80a80ea56811 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 30 Jun 2026 09:23:16 +0600 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=86=E9=A2=91=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20checkbox=20=E9=80=89=E6=8B=A9=E5=88=97?= =?UTF-8?q?=E5=92=8C=E5=85=A8=E9=80=89=E6=8C=89=E9=92=AE=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20PlayInfo=20=E8=A7=A3=E7=A0=81=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E4=B8=8B=E8=BD=BD=E9=9D=A2=E6=9D=BF=E6=97=A0?= =?UTF-8?q?=E9=80=89=E9=A1=B9=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PlayInfo 添加 CodingKeys 映射 PascalCase JSON 字段(PlayURL/Definition/Duration/Size/Format)\n- Table 第一列增加圆形 checkbox 图标,点击可切换选中状态\n- 增加全选/取消全选按钮\n- prepareDownload 增加错误提示\n- 下载面板无播放地址时显示提示文字 --- apps/macos/VODManager/Package.swift | 2 ++ .../Sources/VODManager/Models/Models.swift | 8 +++++ .../VODManager/Views/DownloadPanelView.swift | 19 +++++++----- .../VODManager/Views/VideoListView.swift | 30 +++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/apps/macos/VODManager/Package.swift b/apps/macos/VODManager/Package.swift index 4699b45..ac9dc06 100644 --- a/apps/macos/VODManager/Package.swift +++ b/apps/macos/VODManager/Package.swift @@ -14,3 +14,5 @@ let package = Package( ), ] ) + + diff --git a/apps/macos/VODManager/Sources/VODManager/Models/Models.swift b/apps/macos/VODManager/Sources/VODManager/Models/Models.swift index 14aef77..07c08fe 100644 --- a/apps/macos/VODManager/Sources/VODManager/Models/Models.swift +++ b/apps/macos/VODManager/Sources/VODManager/Models/Models.swift @@ -131,6 +131,14 @@ struct PlayInfo: Codable, Equatable { var duration: String? var size: Int64? var format: String? + + enum CodingKeys: String, CodingKey { + case playURL = "PlayURL" + case definition = "Definition" + case duration = "Duration" + case size = "Size" + case format = "Format" + } } struct CategoryItem: Identifiable, Codable, Equatable { diff --git a/apps/macos/VODManager/Sources/VODManager/Views/DownloadPanelView.swift b/apps/macos/VODManager/Sources/VODManager/Views/DownloadPanelView.swift index 1d7c956..3cc47ff 100644 --- a/apps/macos/VODManager/Sources/VODManager/Views/DownloadPanelView.swift +++ b/apps/macos/VODManager/Sources/VODManager/Views/DownloadPanelView.swift @@ -37,15 +37,20 @@ struct DownloadPanelView: View { Text(item.video.title) .lineLimit(1) Spacer() - Picker("清晰度", selection: Binding( - get: { selectedDefinitions[item.video.videoId] ?? item.playInfos.first?.definition ?? "" }, - set: { selectedDefinitions[item.video.videoId] = $0 } - )) { - ForEach(item.playInfos, id: \.definition) { info in - Text("\(info.definition) - \(formatSize(info.size))").tag(info.definition) + if item.playInfos.isEmpty { + Text("无可用播放地址") + .foregroundStyle(.secondary) + } else { + Picker("清晰度", selection: Binding( + get: { selectedDefinitions[item.video.videoId] ?? item.playInfos.first?.definition ?? "" }, + set: { selectedDefinitions[item.video.videoId] = $0 } + )) { + ForEach(item.playInfos, id: \.definition) { info in + Text("\(info.definition) - \(formatSize(info.size))").tag(info.definition) + } } + .frame(width: 200) } - .frame(width: 200) } } } diff --git a/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift b/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift index 9a9b444..18694cc 100644 --- a/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift +++ b/apps/macos/VODManager/Sources/VODManager/Views/VideoListView.swift @@ -38,6 +38,14 @@ struct VideoListView: View { } .disabled(selectedVideos.isEmpty || isLoading) + Button("全选") { + if selectedVideos.count == videos.count { + selectedVideos.removeAll() + } else { + selectedVideos = Set(videos.map(\.videoId)) + } + } + Button("批量删除") { Task { await batchDelete() } } @@ -65,6 +73,19 @@ struct VideoListView: View { } Table(of: VideoItem.self, selection: $selectedVideos) { + TableColumn("") { video in + Image(systemName: selectedVideos.contains(video.videoId) ? "checkmark.circle.fill" : "circle") + .foregroundStyle(selectedVideos.contains(video.videoId) ? .blue : .secondary) + .onTapGesture { + if selectedVideos.contains(video.videoId) { + selectedVideos.remove(video.videoId) + } else { + selectedVideos.insert(video.videoId) + } + } + } + .width(min: 30, ideal: 30, max: 30) + TableColumn("标题") { video in HStack { AsyncImage(url: video.coverURL.flatMap(URL.init)) { image in @@ -172,15 +193,24 @@ struct VideoListView: View { private func prepareDownload() async { isLoading = true + errorMessage = nil var results: [(video: VideoItem, playInfos: [PlayInfo])] = [] + var errors: [String] = [] for video in videos where selectedVideos.contains(video.videoId) { do { let response = try await VODClient.shared.getPlayInfo(videoId: video.videoId) results.append((video, response.playInfos)) + if response.playInfos.isEmpty { + errors.append("「\(video.title)」无可用播放地址") + } } catch { results.append((video, [])) + errors.append("「\(video.title)」获取播放信息失败:\(error.localizedDescription)") } } + if !errors.isEmpty { + errorMessage = errors.joined(separator: "\n") + } downloadResults = results showDownloadPanel = true isLoading = false