重构相册详情为信息卡片、Tab 筛选、排序、批量删除与底部上传栏;修复网格重叠、禁用按钮蒙层,并支持点击预览大图。同步扩展素材列表 API 与 ViewModel 分页逻辑,并优化有线传图缩略图与传输性能。 Co-authored-by: Cursor <cursoragent@cursor.com>
124 lines
4.6 KiB
Swift
124 lines
4.6 KiB
Swift
//
|
|
// WiredTransferPhotoRow.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import Kingfisher
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
/// 有线传图照片列表行。
|
|
struct WiredTransferPhotoRow: View {
|
|
let photo: WiredTransferPhotoItem
|
|
let selectUploadMode: Bool
|
|
let selected: Bool
|
|
let onToggleSelection: () -> Void
|
|
let onPhotoClick: () -> Void
|
|
let onRetry: () -> Void
|
|
let onDelete: () -> Void
|
|
|
|
private var canSelect: Bool { photo.canSelectForSpecifyUpload }
|
|
private var canRetry: Bool { photo.status == .failed || photo.status == .pending }
|
|
private var rowOpacity: Double { selectUploadMode && !canSelect ? 0.45 : 1 }
|
|
|
|
var body: some View {
|
|
VStack(spacing: 0) {
|
|
HStack(alignment: .center, spacing: 8) {
|
|
HStack(alignment: .center, spacing: 8) {
|
|
if selectUploadMode {
|
|
WiredTransferSelectIndicator(selected: selected, enabled: canSelect)
|
|
}
|
|
|
|
thumbnailView
|
|
.frame(width: WiredTransferDesign.thumbnailSize, height: WiredTransferDesign.thumbnailSize)
|
|
.clipShape(RoundedRectangle(cornerRadius: WiredTransferDesign.thumbnailCornerRadius))
|
|
.opacity(rowOpacity)
|
|
|
|
VStack(alignment: .leading, spacing: 3) {
|
|
HStack(spacing: 4) {
|
|
Text(photo.fileName)
|
|
.font(.system(size: 12, weight: .medium))
|
|
.foregroundStyle(WiredTransferDesign.text333.opacity(rowOpacity))
|
|
.lineLimit(1)
|
|
Spacer(minLength: 0)
|
|
WiredTransferStatusBadge(status: photo.status)
|
|
.opacity(rowOpacity)
|
|
}
|
|
Text(metaText)
|
|
.font(.system(size: 10))
|
|
.foregroundStyle(WiredTransferDesign.text999.opacity(rowOpacity))
|
|
.lineLimit(1)
|
|
}
|
|
}
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.contentShape(Rectangle())
|
|
.onTapGesture {
|
|
if selectUploadMode {
|
|
if canSelect { onToggleSelection() }
|
|
} else {
|
|
onPhotoClick()
|
|
}
|
|
}
|
|
|
|
if !selectUploadMode {
|
|
Menu {
|
|
Button("重传") { onRetry() }
|
|
.disabled(!canRetry)
|
|
Button("删除", role: .destructive) { onDelete() }
|
|
} label: {
|
|
Image(systemName: "ellipsis")
|
|
.font(.system(size: 16))
|
|
.foregroundStyle(WiredTransferDesign.text666)
|
|
.frame(width: 32, height: 32)
|
|
.rotationEffect(.degrees(90))
|
|
}
|
|
}
|
|
}
|
|
.padding(.horizontal, 10)
|
|
.padding(.vertical, 8)
|
|
|
|
if photo.status == .transferring || photo.status == .uploading {
|
|
ProgressView(value: Double(photo.progress), total: 100)
|
|
.tint(AppDesign.primary)
|
|
.frame(height: WiredTransferDesign.progressBarHeight)
|
|
.padding(.horizontal, 10)
|
|
.padding(.bottom, 8)
|
|
}
|
|
}
|
|
}
|
|
|
|
private var metaText: String {
|
|
if photo.resolutionText.isEmpty { return photo.fileSizeText }
|
|
return "\(photo.fileSizeText) \(photo.resolutionText)"
|
|
}
|
|
|
|
@ViewBuilder
|
|
private var thumbnailView: some View {
|
|
if let url = URL(string: photo.thumbnailURL), !photo.thumbnailURL.isEmpty {
|
|
KFImage(url)
|
|
.placeholder { thumbnailPlaceholder }
|
|
.setProcessor(
|
|
DownsamplingImageProcessor(
|
|
size: CGSize(
|
|
width: WiredTransferDesign.thumbnailSize,
|
|
height: WiredTransferDesign.thumbnailSize
|
|
)
|
|
)
|
|
)
|
|
.scaleFactor(UIScreen.main.scale)
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fill)
|
|
} else {
|
|
thumbnailPlaceholder
|
|
}
|
|
}
|
|
|
|
private var thumbnailPlaceholder: some View {
|
|
WiredTransferDesign.pageBackground
|
|
.overlay {
|
|
Image(systemName: "photo")
|
|
.foregroundStyle(WiredTransferDesign.text999)
|
|
}
|
|
}
|
|
}
|