// // WiredTransferPhotoRow.swift // suixinkan // 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) { if selectUploadMode { Button(action: onToggleSelection) { WiredTransferSelectIndicator(selected: selected, enabled: canSelect) } .buttonStyle(.plain) .disabled(!canSelect) } thumbnailView .frame(width: WiredTransferDesign.thumbnailSize, height: WiredTransferDesign.thumbnailSize) .clipShape(RoundedRectangle(cornerRadius: WiredTransferDesign.thumbnailCornerRadius)) .opacity(rowOpacity) .onTapGesture { if !selectUploadMode { onPhotoClick() } } 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) } 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) .contentShape(Rectangle()) .onTapGesture { if selectUploadMode, canSelect { onToggleSelection() } } 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 photo.thumbnailURL.hasPrefix("file://"), let url = URL(string: photo.thumbnailURL) { if let uiImage = UIImage(contentsOfFile: url.path) { Image(uiImage: uiImage) .resizable() .aspectRatio(contentMode: .fill) } else { thumbnailPlaceholder } } else if !photo.thumbnailURL.isEmpty { RemoteImage(urlString: photo.thumbnailURL) { thumbnailPlaceholder } } else { thumbnailPlaceholder } } private var thumbnailPlaceholder: some View { WiredTransferDesign.pageBackground .overlay { Image(systemName: "photo") .foregroundStyle(WiredTransferDesign.text999) } } }