feat: redesign travel album management
This commit is contained in:
@@ -277,4 +277,22 @@ enum TravelAlbumDisplayFormatter {
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
/// 将服务端创建时间格式化为摘要卡使用的 `yyyy/MM/dd HH:mm`。
|
||||
static func creationTimeText(_ text: String) -> String {
|
||||
guard !text.isEmpty else { return "--" }
|
||||
let normalized = text.replacingOccurrences(of: "T", with: " ")
|
||||
guard normalized.count >= 16 else { return normalized }
|
||||
return String(normalized.prefix(16)).replacingOccurrences(of: "-", with: "/")
|
||||
}
|
||||
|
||||
/// 计算相册摘要卡封面,按相册、素材缩略图、素材原图顺序回退。
|
||||
static func albumCoverURL(album: TravelAlbum?, materials: [TravelAlbumMaterial]) -> String {
|
||||
if let coverURL = album?.coverUrl.trimmingCharacters(in: .whitespacesAndNewlines), !coverURL.isEmpty {
|
||||
return coverURL
|
||||
}
|
||||
guard let first = materials.first else { return "" }
|
||||
let materialCover = first.coverUrl.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return materialCover.isEmpty ? first.fileUrl.trimmingCharacters(in: .whitespacesAndNewlines) : materialCover
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,21 @@ final class TravelAlbumDetailViewModel {
|
||||
case .fileNameDesc: "文件名倒序"
|
||||
}
|
||||
}
|
||||
|
||||
var compactTitle: String {
|
||||
switch self {
|
||||
case .createdAsc: "时间 ↑"
|
||||
case .createdDesc: "时间 ↓"
|
||||
case .fileNameAsc: "名称 ↑"
|
||||
case .fileNameDesc: "名称 ↓"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var album: TravelAlbum?
|
||||
private(set) var materials: [TravelAlbumMaterial] = []
|
||||
private(set) var allPhotoCount = 0
|
||||
private(set) var purchasedPhotoCount = 0
|
||||
private(set) var selectedTab: Tab = .all
|
||||
private(set) var sortOption: SortOption = .createdDesc
|
||||
private(set) var isLoading = true
|
||||
@@ -65,6 +75,7 @@ final class TravelAlbumDetailViewModel {
|
||||
notifyStateChange()
|
||||
await loadAlbumInfo(api: api)
|
||||
await loadAllPhotoCount(api: api)
|
||||
await loadPurchasedPhotoCount(api: api)
|
||||
await loadMaterials(reset: true, api: api)
|
||||
isRefreshing = false
|
||||
isLoading = false
|
||||
@@ -102,6 +113,30 @@ final class TravelAlbumDetailViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// 拉取已购照片数量;失败时保留已有数量,不影响素材列表加载。
|
||||
func loadPurchasedPhotoCount(api: any TravelAlbumServing) async {
|
||||
do {
|
||||
let response = try await api.materialList(
|
||||
userEquityTravelId: albumId,
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
orderBy: sortOption.rawValue,
|
||||
isPurchased: 1
|
||||
)
|
||||
purchasedPhotoCount = response.total
|
||||
notifyStateChange()
|
||||
} catch is CancellationError {
|
||||
return
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/// 摘要卡封面地址,依次回退相册封面、首张素材封面和首张素材原图。
|
||||
var displayCoverURL: String {
|
||||
TravelAlbumDisplayFormatter.albumCoverURL(album: album, materials: materials)
|
||||
}
|
||||
|
||||
/// 切换素材 tab。
|
||||
func selectTab(_ tab: Tab, api: any TravelAlbumServing) async {
|
||||
guard selectedTab != tab else { return }
|
||||
@@ -144,6 +179,8 @@ final class TravelAlbumDetailViewModel {
|
||||
canLoadMore = materials.count < response.total
|
||||
if selectedTab == .all {
|
||||
allPhotoCount = response.total
|
||||
} else {
|
||||
purchasedPhotoCount = response.total
|
||||
}
|
||||
isLoadingMore = false
|
||||
notifyStateChange()
|
||||
|
||||
Reference in New Issue
Block a user