重构相册详情为信息卡片、Tab 筛选、排序、批量删除与底部上传栏;修复网格重叠、禁用按钮蒙层,并支持点击预览大图。同步扩展素材列表 API 与 ViewModel 分页逻辑,并优化有线传图缩略图与传输性能。 Co-authored-by: Cursor <cursoragent@cursor.com>
85 lines
2.5 KiB
Swift
85 lines
2.5 KiB
Swift
//
|
||
// CameraTransferTask.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/6/29.
|
||
//
|
||
|
||
import Foundation
|
||
|
||
/// 相机传输任务状态。
|
||
enum CameraTransferStatus: String, Codable, Equatable {
|
||
case pending
|
||
case downloading
|
||
case downloaded
|
||
case uploading
|
||
case uploaded
|
||
case failed
|
||
}
|
||
|
||
/// 相机传输任务,表示从相机下载到上传登记的单条记录。
|
||
struct CameraTransferTask: Identifiable, Equatable, Codable {
|
||
let id: UUID
|
||
let assetID: String
|
||
let filename: String
|
||
var localPath: String?
|
||
var remoteURL: String?
|
||
/// 相机文件拍摄时间,格式 `yyyy-MM-dd HH:mm:ss`。
|
||
var capturedAt: String?
|
||
var status: CameraTransferStatus
|
||
var progress: Int
|
||
var errorMessage: String?
|
||
|
||
init(
|
||
id: UUID = UUID(),
|
||
assetID: String,
|
||
filename: String,
|
||
localPath: String? = nil,
|
||
remoteURL: String? = nil,
|
||
capturedAt: String? = nil,
|
||
status: CameraTransferStatus = .pending,
|
||
progress: Int = 0,
|
||
errorMessage: String? = nil
|
||
) {
|
||
self.id = id
|
||
self.assetID = assetID
|
||
self.filename = filename
|
||
self.localPath = localPath
|
||
self.remoteURL = remoteURL
|
||
self.capturedAt = capturedAt
|
||
self.status = status
|
||
self.progress = progress
|
||
self.errorMessage = errorMessage
|
||
}
|
||
|
||
/// 将日期格式化为列表使用的拍摄时间字符串。
|
||
static func capturedAtString(from date: Date?) -> String {
|
||
Self.capturedAtFormatter.string(from: date ?? Date())
|
||
}
|
||
|
||
/// 从本地文件推断拍摄时间。
|
||
static func capturedAtString(forLocalPath path: String) -> String? {
|
||
guard let url = CameraDownloadStorage.resolveLocalURL(from: path),
|
||
FileManager.default.fileExists(atPath: url.path),
|
||
let attributes = try? FileManager.default.attributesOfItem(atPath: url.path)
|
||
else { return nil }
|
||
|
||
let date = (attributes[.creationDate] as? Date)
|
||
?? (attributes[.modificationDate] as? Date)
|
||
return date.map { capturedAtString(from: $0) }
|
||
}
|
||
|
||
private static let capturedAtFormatter: DateFormatter = {
|
||
let formatter = DateFormatter()
|
||
formatter.locale = Locale(identifier: "zh_CN")
|
||
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
|
||
return formatter
|
||
}()
|
||
|
||
/// 本地文件 URL,支持相对路径与旧版绝对路径。
|
||
var localURL: URL? {
|
||
guard let localPath, !localPath.isEmpty else { return nil }
|
||
return CameraDownloadStorage.resolveLocalURL(from: localPath)
|
||
}
|
||
}
|