Files
suixinkan_ios_new/suixinkan/Features/TravelAlbum/Views/WiredTransfer/WiredTransferPhotoRow.swift
汉秋 660852ffad 增强有线传图手动上传并发能力,并稳定列表行布局。
指定/勾选/批量上传支持恢复仅本地持久化的待传照片,手动上传与 pipeline 均按 3 路并发;pipeline 任务签名去重避免状态回退,照片行固定高度并预留进度条占位。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 15:10:47 +08:00

123 lines
4.4 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 }
private var showsProgress: Bool { photo.status == .transferring || photo.status == .uploading }
var body: some View {
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: 5) {
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)
progressSlot
}
}
.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))
}
}
}
.frame(height: WiredTransferDesign.photoRowHeight)
.padding(.horizontal, 10)
}
private var metaText: String {
if photo.resolutionText.isEmpty { return photo.fileSizeText }
return "\(photo.fileSizeText) \(photo.resolutionText)"
}
private var progressSlot: some View {
ProgressView(value: showsProgress ? Double(photo.progress) : 0, total: 100)
.tint(AppDesign.primary)
.opacity(showsProgress ? 1 : 0)
.frame(height: WiredTransferDesign.progressBarHeight)
}
@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)
}
}
}