对齐旅拍相册详情页 Android UI,并修复网格预览与布局问题。

重构相册详情为信息卡片、Tab 筛选、排序、批量删除与底部上传栏;修复网格重叠、禁用按钮蒙层,并支持点击预览大图。同步扩展素材列表 API 与 ViewModel 分页逻辑,并优化有线传图缩略图与传输性能。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-30 13:53:59 +08:00
parent c71b45bdfd
commit 5e620623eb
23 changed files with 2000 additions and 288 deletions

View File

@ -161,6 +161,18 @@ struct TravelAlbumMaterial: Decodable, Identifiable, Equatable {
createdAt = container.lossyString(forKey: .createdAt)
updatedAt = container.lossyString(forKey: .updatedAt)
}
/// URL
var previewURLString: String {
if !fileURL.isEmpty { return fileURL }
return coverURL
}
/// URL
var thumbnailURLString: String {
if !coverURL.isEmpty { return coverURL }
return fileURL
}
}
///
@ -308,7 +320,10 @@ struct WiredTransferPhotoItem: Identifiable, Equatable {
let id: String
let sourceId: String
let fileName: String
/// 使 URL
let thumbnailURL: String
/// 使 URL
let previewURL: String
let capturedAt: String
let fileSizeText: String
let resolutionText: String
@ -321,6 +336,7 @@ struct WiredTransferPhotoItem: Identifiable, Equatable {
sourceId: String? = nil,
fileName: String,
thumbnailURL: String,
previewURL: String = "",
capturedAt: String,
fileSizeText: String,
resolutionText: String = "",
@ -332,6 +348,7 @@ struct WiredTransferPhotoItem: Identifiable, Equatable {
self.sourceId = sourceId ?? id
self.fileName = fileName
self.thumbnailURL = thumbnailURL
self.previewURL = previewURL
self.capturedAt = capturedAt
self.fileSizeText = fileSizeText
self.resolutionText = resolutionText
@ -385,8 +402,15 @@ struct WiredTransferPhotoRecord: Codable, Equatable {
let updatedAt: TimeInterval
func toPhotoItem() -> WiredTransferPhotoItem {
let previewCandidates = [thumbnailPath, localPath, remoteURL]
let thumbnailURL = previewCandidates.compactMap { path -> String? in
let thumbnailCandidates = [thumbnailPath, remoteURL]
let thumbnailURL = thumbnailCandidates.compactMap { path -> String? in
guard !path.isEmpty else { return nil }
if path.hasPrefix("http") { return path }
let preview = CameraDownloadStorage.previewURLString(from: path)
return preview.isEmpty ? nil : preview
}.first ?? ""
let previewCandidates = [localPath, remoteURL, thumbnailPath]
let previewURL = previewCandidates.compactMap { path -> String? in
guard !path.isEmpty else { return nil }
if path.hasPrefix("http") { return path }
let preview = CameraDownloadStorage.previewURLString(from: path)
@ -398,6 +422,7 @@ struct WiredTransferPhotoRecord: Codable, Equatable {
sourceId: sourceId,
fileName: fileName,
thumbnailURL: thumbnailURL,
previewURL: previewURL,
capturedAt: capturedAt,
fileSizeText: Self.formatFileSize(fileSizeBytes),
status: WiredTransferUploadStatus(rawValue: status) ?? .pending,
@ -465,6 +490,16 @@ extension Array where Element == WiredTransferPhotoItem {
Set(filter { $0.canSelectForSpecifyUpload }.map(\.id))
}
///
func sortedByCaptureTimeDescending() -> [WiredTransferPhotoItem] {
sorted { lhs, rhs in
let leftDate = lhs.capturedDate() ?? .distantPast
let rightDate = rhs.capturedDate() ?? .distantPast
if leftDate != rightDate { return leftDate > rightDate }
return lhs.id > rhs.id
}
}
/// 30
func buildPhotoSections() -> [WiredTransferPhotoSection] {
let grouped = Dictionary(grouping: compactMap { photo -> (Date, WiredTransferPhotoItem)? in