feat: 完善相册 AI 修图模板选择流程

This commit is contained in:
2026-08-11 15:22:08 +08:00
parent 43c75c8e36
commit e64dcec094
11 changed files with 261 additions and 202 deletions
+30 -24
View File
@@ -206,39 +206,29 @@ final class TravelAlbumDetailViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.purchasedPhotoCount, 0)
}
func testPreviewReloadRefetchesAllLoadedPagesAndReplacesMaterialsById() async throws {
func testRefreshMaterialUpdatesOnlyMatchingCachedMaterial() async throws {
let api = TravelAlbumMockAPI()
api.materialListResponses = [
TravelAlbumListResponse(
total: 35,
list: (1 ... 30).map { TravelAlbumMaterial(id: $0) }
),
TravelAlbumListResponse(
total: 35,
list: (31 ... 35).map { TravelAlbumMaterial(id: $0) }
),
TravelAlbumListResponse(
total: 35,
list: (1 ... 30).map {
TravelAlbumMaterial(id: $0, aiRetouchBatchId: $0 == 7 ? 700 : 0)
}
),
TravelAlbumListResponse(
total: 35,
list: (31 ... 35).map { TravelAlbumMaterial(id: $0) }
total: 2,
list: [TravelAlbumMaterial(id: 7), TravelAlbumMaterial(id: 8)]
),
]
api.materialInfoResponse = TravelAlbumMaterial(
id: 7,
aiRetouchBatchId: 700,
aiRefinedURL: "https://cdn/refined.jpg"
)
let viewModel = TravelAlbumDetailViewModel(albumId: 2)
await viewModel.loadMaterials(reset: true, api: api)
await viewModel.loadMaterials(reset: false, api: api)
let response = try await viewModel.reloadLoadedMaterials(api: api)
let material = try await viewModel.refreshMaterial(id: 7, api: api)
XCTAssertEqual(response.total, 35)
XCTAssertEqual(response.list.count, 35)
XCTAssertEqual(response.list.first { $0.id == 7 }?.aiRetouchBatchId, 700)
XCTAssertEqual(api.materialRequests.suffix(2).map(\.page), [1, 2])
XCTAssertEqual(api.materialRequests.suffix(2).map(\.pageSize), [30, 30])
XCTAssertEqual(material.aiRetouchBatchId, 700)
XCTAssertEqual(viewModel.materials.first { $0.id == 7 }?.aiRefinedURL, "https://cdn/refined.jpg")
XCTAssertEqual(viewModel.materials.first { $0.id == 8 }?.aiRetouchBatchId, 0)
XCTAssertEqual(api.materialInfoRequests, [.init(userEquityTravelId: 2, materialId: 7)])
XCTAssertEqual(api.materialRequests.count, 1)
}
func testDeleteAlbumCallsCallback() async {
@@ -1074,12 +1064,19 @@ final class TravelAlbumMockAPI: TravelAlbumServing {
let isPurchased: Int?
}
struct MaterialInfoRequest: Equatable {
let userEquityTravelId: Int
let materialId: Int
}
var availableOrdersResponse: [TravelAlbumAvailableOrder] = []
var listResponse = TravelAlbumListResponse<TravelAlbum>()
var createResponse = TravelAlbumCreateResponse(id: 0)
var infoResponse = TravelAlbum()
var materialListResponses: [TravelAlbumListResponse<TravelAlbumMaterial>] = []
var materialListFailingCallIndexes: Set<Int> = []
var materialInfoResponse = TravelAlbumMaterial()
var materialInfoError: Error?
var uploadMaterialResponse = TravelAlbumMaterial()
var materialClientPhotoIdsResponse = TravelAlbumMaterialClientPhotoIDsResponse(clientPhotoIds: [])
var mpCodeResponse = TravelAlbumMpCodeResponse(mpCodeOssUrl: "")
@@ -1096,6 +1093,7 @@ final class TravelAlbumMockAPI: TravelAlbumServing {
private(set) var availableOrdersCallCount = 0
private(set) var createRequests: [TravelAlbumCreateRequest] = []
private(set) var materialRequests: [MaterialRequest] = []
private(set) var materialInfoRequests: [MaterialInfoRequest] = []
private(set) var uploadMaterialRequests: [TravelAlbumUploadMaterialRequest] = []
private(set) var materialClientPhotoIdsCallCount = 0
private(set) var deletedAlbumIds: [Int] = []
@@ -1147,6 +1145,14 @@ final class TravelAlbumMockAPI: TravelAlbumServing {
return materialListResponses.removeFirst()
}
func materialInfo(userEquityTravelId: Int, materialId: Int) async throws -> TravelAlbumMaterial {
materialInfoRequests.append(
MaterialInfoRequest(userEquityTravelId: userEquityTravelId, materialId: materialId)
)
if let materialInfoError { throw materialInfoError }
return materialInfoResponse
}
func uploadMaterial(_ request: TravelAlbumUploadMaterialRequest) async throws -> TravelAlbumMaterial {
uploadMaterialRequests.append(request)
return uploadMaterialResponse