Files
suixinkan_ios_new/suixinkan/Features/TravelAlbum/Views/WiredTransfer/WiredTransferPhotoRow.swift
汉秋 5e620623eb 对齐旅拍相册详情页 Android UI,并修复网格预览与布局问题。
重构相册详情为信息卡片、Tab 筛选、排序、批量删除与底部上传栏;修复网格重叠、禁用按钮蒙层,并支持点击预览大图。同步扩展素材列表 API 与 ViewModel 分页逻辑,并优化有线传图缩略图与传输性能。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 13:53:59 +08:00

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)
}
}
}