Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5704531f3a | ||
|
|
87819780c9 |
@@ -197,7 +197,7 @@ protocol TravelAlbumPreviewActionHandling: AnyObject {
|
||||
/// 新接口接入前的占位操作实现,不修改任何业务数据。
|
||||
final class PlaceholderTravelAlbumPreviewActionHandler: TravelAlbumPreviewActionHandling {
|
||||
func requestAIRetouch(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
|
||||
.unavailable("AI修复功能待接口接入")
|
||||
.unavailable("AI修图功能待接口接入")
|
||||
}
|
||||
|
||||
func deleteProject(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
|
||||
|
||||
@@ -14,7 +14,7 @@ final class TravelAlbumPreviewActionHandler: TravelAlbumPreviewActionHandling {
|
||||
self.api = api
|
||||
}
|
||||
|
||||
/// AI 修复仍由相册选择态的模板流程发起。
|
||||
/// AI 修图仍由相册选择态的模板流程发起。
|
||||
func requestAIRetouch(originalMaterialId: Int) async -> TravelAlbumPreviewActionResult {
|
||||
.unavailable("请在相册中选择照片后使用AI修图")
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
||||
private let purchasedTabButton = UIButton(type: .system)
|
||||
private let sortButton = UIButton(type: .system)
|
||||
private let selectButton = UIButton(type: .system)
|
||||
private let refreshControl = UIRefreshControl()
|
||||
private var collectionView: UICollectionView!
|
||||
private var dataSource: UICollectionViewDiffableDataSource<Int, TravelAlbumMaterial>!
|
||||
private let bottomBar = UIView()
|
||||
@@ -97,6 +98,9 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
||||
collectionView.alwaysBounceVertical = true
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.delegate = self
|
||||
refreshControl.tintColor = TravelAlbumDetailStyle.primary
|
||||
refreshControl.accessibilityIdentifier = "travelAlbum.refreshControl"
|
||||
collectionView.refreshControl = refreshControl
|
||||
collectionView.register(
|
||||
TravelAlbumMaterialCell.self,
|
||||
forCellWithReuseIdentifier: TravelAlbumMaterialCell.reuseIdentifier
|
||||
@@ -225,6 +229,7 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
||||
aiRetouchButton.addTarget(self, action: #selector(aiRetouchTapped), for: .touchUpInside)
|
||||
deleteSelectedButton.addTarget(self, action: #selector(deleteSelectedTapped), for: .touchUpInside)
|
||||
uploadButton.addTarget(self, action: #selector(uploadTapped), for: .touchUpInside)
|
||||
refreshControl.addTarget(self, action: #selector(refreshPulled), for: .valueChanged)
|
||||
viewModel.onStateChange = { [weak self] in
|
||||
Task { @MainActor in self?.applyViewModel() }
|
||||
}
|
||||
@@ -291,13 +296,20 @@ final class TravelAlbumDetailViewController: BaseViewController {
|
||||
}
|
||||
dataSource.apply(snapshot, animatingDifferences: true)
|
||||
|
||||
if viewModel.isLoading && viewModel.album == nil {
|
||||
if !viewModel.isRefreshing {
|
||||
refreshControl.endRefreshing()
|
||||
}
|
||||
if viewModel.isLoading && viewModel.album == nil && !refreshControl.isRefreshing {
|
||||
showLoading()
|
||||
} else {
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func refreshPulled() {
|
||||
Task { await viewModel.refreshAll(api: api) }
|
||||
}
|
||||
|
||||
private func configureTabButtonBase(_ button: UIButton) {
|
||||
button.titleLabel?.font = .systemFont(ofSize: 13, weight: .medium)
|
||||
button.accessibilityTraits.insert(.button)
|
||||
|
||||
@@ -193,7 +193,7 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
|
||||
}
|
||||
|
||||
private func configureActions() {
|
||||
let aiButton = makeActionButton(title: "AI修复", systemName: "wand.and.stars", color: UIColor(hex: 0x60A5FA))
|
||||
let aiButton = makeActionButton(title: "AI修图", systemName: "wand.and.stars", color: UIColor(hex: 0x60A5FA))
|
||||
let deleteConfiguration = makeActionButton(
|
||||
title: "删除",
|
||||
systemName: "trash",
|
||||
|
||||
@@ -7,9 +7,50 @@ import UIKit
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
/// 相册管理页选择态底部操作区测试。
|
||||
/// 相册管理页刷新、预览与选择态交互测试。
|
||||
@MainActor
|
||||
final class TravelAlbumDetailViewControllerTests: XCTestCase {
|
||||
func testPullToRefreshReloadsGridAndEndsRefreshing() async throws {
|
||||
let api = TravelAlbumMockAPI()
|
||||
api.infoResponse = TravelAlbum(id: 2, name: "测试相册")
|
||||
api.materialListResponses = [
|
||||
TravelAlbumListResponse(total: 1, list: []),
|
||||
TravelAlbumListResponse(total: 0, list: []),
|
||||
TravelAlbumListResponse(total: 1, list: [TravelAlbumMaterial(id: 1)]),
|
||||
TravelAlbumListResponse(total: 2, list: []),
|
||||
TravelAlbumListResponse(total: 1, list: []),
|
||||
TravelAlbumListResponse(
|
||||
total: 2,
|
||||
list: [TravelAlbumMaterial(id: 1), TravelAlbumMaterial(id: 2)]
|
||||
),
|
||||
]
|
||||
let controller = TravelAlbumDetailViewController(albumId: 2, api: api)
|
||||
let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 390, height: 844))
|
||||
window.rootViewController = controller
|
||||
window.makeKeyAndVisible()
|
||||
defer { window.isHidden = true }
|
||||
controller.loadViewIfNeeded()
|
||||
controller.view.layoutIfNeeded()
|
||||
let collectionView = try XCTUnwrap(
|
||||
controller.view.findSubview { $0 is UICollectionView } as? UICollectionView
|
||||
)
|
||||
let refreshControl = try XCTUnwrap(collectionView.refreshControl)
|
||||
await waitUntil { api.materialRequests.count == 3 }
|
||||
|
||||
refreshControl.beginRefreshing()
|
||||
XCTAssertTrue(refreshControl.isRefreshing)
|
||||
refreshControl.sendActions(for: .valueChanged)
|
||||
await waitUntil {
|
||||
api.materialRequests.count == 6
|
||||
&& !refreshControl.isRefreshing
|
||||
&& collectionView.numberOfItems(inSection: 0) == 2
|
||||
}
|
||||
|
||||
XCTAssertEqual(refreshControl.accessibilityIdentifier, "travelAlbum.refreshControl")
|
||||
XCTAssertEqual(collectionView.numberOfItems(inSection: 0), 2)
|
||||
XCTAssertFalse(refreshControl.isRefreshing)
|
||||
}
|
||||
|
||||
func testPreviewDeleteHandlerCallsMaterialAPIAndPreservesServerFailure() async {
|
||||
let api = TravelAlbumMockAPI()
|
||||
let handler = TravelAlbumPreviewActionHandler(api: api)
|
||||
|
||||
@@ -169,7 +169,7 @@ final class TravelAlbumModelsTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(
|
||||
aiResult,
|
||||
.unavailable("AI修复功能待接口接入")
|
||||
.unavailable("AI修图功能待接口接入")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
deleteResult,
|
||||
|
||||
Reference in New Issue
Block a user