feat: 优化相册图片预览交互

This commit is contained in:
2026-08-12 10:58:53 +08:00
parent 010add828b
commit 05cfdc3662
2 changed files with 356 additions and 81 deletions
@@ -44,11 +44,16 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
private let counterLabel = UILabel()
private let bottomChrome = UIView()
private let divider = UIView()
private let tabStack = UIStackView()
private let variantControls = UIView()
private let variantSegmentedControl = UISegmentedControl()
private let highResolutionButton = UIButton(type: .system)
private let actionStack = UIStackView()
private let deleteButton = UIButton(type: .system)
private let refreshButton = UIButton(type: .system)
private var tabHeightConstraint: Constraint?
private var variantControlsHeightConstraint: Constraint?
private var didConfigureVariantControls = false
private var showsVariantControls = false
private var variantControlsAnimationGeneration = 0
/// 创建全屏预览页。
init(
@@ -84,7 +89,8 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
fatalError("init(coder:) has not been implemented")
}
override var prefersStatusBarHidden: Bool { true }
override var prefersStatusBarHidden: Bool { false }
override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent }
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge { [.bottom] }
override func viewDidLoad() {
@@ -114,6 +120,7 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
collectionView.isPagingEnabled = true
collectionView.alwaysBounceHorizontal = nodes.count > 1
collectionView.showsHorizontalScrollIndicator = false
collectionView.accessibilityIdentifier = "travelAlbum.previewCollectionView"
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(
@@ -121,34 +128,57 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
forCellWithReuseIdentifier: TravelAlbumPreviewImageCell.reuseIdentifier
)
topChrome.backgroundColor = UIColor.black.withAlphaComponent(0.72)
bottomChrome.backgroundColor = UIColor.black.withAlphaComponent(0.78)
divider.backgroundColor = UIColor.white.withAlphaComponent(0.2)
topChrome.backgroundColor = .black
topChrome.accessibilityIdentifier = "travelAlbum.previewTopChrome"
bottomChrome.backgroundColor = .black
bottomChrome.accessibilityIdentifier = "travelAlbum.previewBottomChrome"
divider.backgroundColor = UIColor.white.withAlphaComponent(0.12)
closeButton.setImage(UIImage(systemName: "chevron.down", withConfiguration: UIImage.SymbolConfiguration(weight: .semibold)), for: .normal)
closeButton.tintColor = .white
var backConfiguration = UIButton.Configuration.plain()
backConfiguration.image = UIImage(systemName: "chevron.backward")
backConfiguration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(
pointSize: 21,
weight: .semibold
)
backConfiguration.baseForegroundColor = .white
backConfiguration.contentInsets = .zero
closeButton.configuration = backConfiguration
closeButton.accessibilityLabel = "关闭图片预览"
closeButton.accessibilityIdentifier = "travelAlbum.previewBackButton"
closeButton.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
titleLabel.textColor = .white
titleLabel.font = .systemFont(ofSize: 15, weight: .medium)
titleLabel.font = .systemFont(ofSize: 17, weight: .semibold)
titleLabel.textAlignment = .center
titleLabel.lineBreakMode = .byTruncatingMiddle
sizeLabel.textColor = UIColor.white.withAlphaComponent(0.65)
sizeLabel.font = .systemFont(ofSize: 11, weight: .regular)
sizeLabel.textColor = UIColor.white.withAlphaComponent(0.52)
sizeLabel.font = .systemFont(ofSize: 13, weight: .regular)
sizeLabel.textAlignment = .center
counterLabel.textColor = .white
counterLabel.font = .monospacedDigitSystemFont(ofSize: 14, weight: .medium)
counterLabel.textAlignment = .right
counterLabel.textColor = UIColor.white.withAlphaComponent(0.82)
counterLabel.font = .monospacedDigitSystemFont(ofSize: 15, weight: .medium)
counterLabel.textAlignment = .center
counterLabel.backgroundColor = UIColor(white: 0.11, alpha: 1)
counterLabel.layer.cornerRadius = 17
counterLabel.clipsToBounds = true
counterLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
tabStack.axis = .horizontal
tabStack.distribution = .fillEqually
tabStack.alignment = .fill
variantSegmentedControl.selectedSegmentTintColor = UIColor(white: 0.22, alpha: 1)
variantSegmentedControl.backgroundColor = UIColor(white: 0.065, alpha: 1)
variantSegmentedControl.setTitleTextAttributes(
[.foregroundColor: UIColor.white.withAlphaComponent(0.62), .font: UIFont.systemFont(ofSize: 15)],
for: .normal
)
variantSegmentedControl.setTitleTextAttributes(
[.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15, weight: .semibold)],
for: .selected
)
variantSegmentedControl.accessibilityIdentifier = "travelAlbum.previewVariantSegmentedControl"
variantSegmentedControl.addTarget(self, action: #selector(segmentChanged(_:)), for: .valueChanged)
actionStack.axis = .horizontal
actionStack.distribution = .fillEqually
actionStack.alignment = .fill
configureHighResolutionButton()
configureActions()
let titleStack = UIStackView(arrangedSubviews: [titleLabel, sizeLabel])
@@ -163,23 +193,25 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
topChrome.addSubview(counterLabel)
view.addSubview(bottomChrome)
bottomChrome.addSubview(divider)
bottomChrome.addSubview(tabStack)
bottomChrome.addSubview(variantControls)
variantControls.addSubview(variantSegmentedControl)
variantControls.addSubview(highResolutionButton)
bottomChrome.addSubview(actionStack)
collectionView.snp.makeConstraints { $0.edges.equalToSuperview() }
topChrome.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.top).offset(64)
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.top).offset(72)
}
closeButton.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(8)
make.bottom.equalToSuperview().offset(-10)
make.leading.equalToSuperview().offset(10)
make.bottom.equalToSuperview().offset(-14)
make.size.equalTo(44)
}
counterLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(16)
make.centerY.equalTo(closeButton)
make.width.greaterThanOrEqualTo(52)
make.width.greaterThanOrEqualTo(48)
make.height.equalTo(34)
}
titleStack.snp.makeConstraints { make in
make.centerY.equalTo(closeButton)
@@ -192,40 +224,72 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
bottomChrome.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
}
collectionView.snp.makeConstraints { make in
make.top.equalTo(topChrome.snp.bottom)
make.leading.trailing.equalToSuperview()
make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-126.5)
}
divider.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(0.5)
}
tabStack.snp.makeConstraints { make in
variantControls.snp.makeConstraints { make in
make.top.equalTo(divider.snp.bottom)
make.leading.trailing.equalToSuperview().inset(12)
tabHeightConstraint = make.height.equalTo(0).constraint
make.leading.trailing.equalToSuperview()
variantControlsHeightConstraint = make.height.equalTo(56).constraint
}
variantSegmentedControl.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.centerY.equalToSuperview()
make.height.equalTo(40)
make.trailing.equalTo(highResolutionButton.snp.leading).offset(-12)
}
highResolutionButton.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(18)
make.centerY.equalToSuperview()
make.width.equalTo(116)
make.height.equalTo(40)
}
actionStack.snp.makeConstraints { make in
make.top.equalTo(tabStack.snp.bottom)
make.top.equalTo(variantControls.snp.bottom)
make.leading.trailing.equalToSuperview().inset(8)
make.height.equalTo(70)
make.bottom.equalTo(view.safeAreaLayoutGuide)
}
}
private func configureHighResolutionButton() {
var configuration = UIButton.Configuration.filled()
configuration.title = "查看高清图"
configuration.baseForegroundColor = .white
configuration.baseBackgroundColor = UIColor(white: 0.18, alpha: 1)
configuration.background.cornerRadius = 20
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in
var attributes = attributes
attributes.font = .systemFont(ofSize: 15, weight: .medium)
return attributes
}
highResolutionButton.configuration = configuration
highResolutionButton.accessibilityLabel = "查看高清图"
highResolutionButton.accessibilityIdentifier = "travelAlbum.previewHighResolutionButton"
highResolutionButton.addTarget(self, action: #selector(highResolutionTapped), for: .touchUpInside)
}
private func configureActions() {
let aiButton = makeActionButton(title: "AI修图", systemName: "wand.and.stars", color: UIColor(hex: 0x60A5FA))
let aiButton = makeActionButton(title: "AI修图", systemName: "tag", color: .white)
let deleteConfiguration = makeActionButton(
title: "删除",
systemName: "trash",
color: UIColor(hex: 0xF87171)
color: .white
).configuration
deleteButton.configuration = deleteConfiguration
deleteButton.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
deleteButton.accessibilityLabel = "删除"
deleteButton.accessibilityIdentifier = "travelAlbum.previewDeleteButton"
refreshButton.configuration = makeActionButton(
title: "刷新",
systemName: "arrow.clockwise",
systemName: "arrow.counterclockwise.circle",
color: .white
).configuration
refreshButton.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
refreshButton.accessibilityLabel = "刷新"
refreshButton.accessibilityIdentifier = "travelAlbum.previewRefreshButton"
aiButton.addTarget(self, action: #selector(aiTapped), for: .touchUpInside)
@@ -239,11 +303,19 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
configuration.title = title
configuration.image = UIImage(systemName: systemName)
configuration.imagePlacement = .top
configuration.imagePadding = 5
configuration.imagePadding = 8
configuration.preferredSymbolConfigurationForImage = UIImage.SymbolConfiguration(
pointSize: 25,
weight: .regular
)
configuration.baseForegroundColor = color
configuration.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6)
configuration.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 6, bottom: 8, trailing: 6)
configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { attributes in
var attributes = attributes
attributes.font = .systemFont(ofSize: 14, weight: .regular)
return attributes
}
let button = UIButton(configuration: configuration)
button.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
button.accessibilityLabel = title
return button
}
@@ -278,45 +350,100 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
sizeLabel.text = TravelAlbumDisplayFormatter.fileSizeText(asset?.fileSize ?? 0)
counterLabel.text = "\(node.projectIndex + 1)/\(max(totalCount, projects.count))"
counterLabel.accessibilityLabel = "第 \(node.projectIndex + 1) 张,共 \(max(totalCount, projects.count)) 张"
highResolutionButton.isEnabled = asset != nil
highResolutionButton.alpha = asset == nil ? 0.45 : 1
rebuildTabs()
loadMoreIfNeeded(projectIndex: node.projectIndex)
}
private func rebuildTabs() {
tabStack.arrangedSubviews.forEach {
tabStack.removeArrangedSubview($0)
$0.removeFromSuperview()
while variantSegmentedControl.numberOfSegments > 0 {
variantSegmentedControl.removeSegment(at: 0, animated: false)
}
guard let project = currentProject, project.hasVariants else {
tabStack.isHidden = true
tabHeightConstraint?.update(offset: 0)
setVariantControlsVisible(false)
return
}
tabStack.isHidden = false
tabHeightConstraint?.update(offset: 44)
let activeKind = currentAsset?.kind ?? .original
for asset in project.orderedAssets {
let button = UIButton(type: .system)
button.tag = asset.kind.rawValue
button.setTitle(asset.kind.title, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 13, weight: asset.kind == activeKind ? .semibold : .medium)
button.setTitleColor(asset.kind == activeKind ? .white : UIColor.white.withAlphaComponent(0.55), for: .normal)
button.backgroundColor = asset.kind == activeKind ? UIColor.white.withAlphaComponent(0.12) : .clear
button.layer.cornerRadius = 8
button.accessibilityLabel = asset.kind.title
button.accessibilityTraits = asset.kind == activeKind ? [.button, .selected] : .button
button.addTarget(self, action: #selector(tabTapped(_:)), for: .touchUpInside)
tabStack.addArrangedSubview(button)
}
view.layoutIfNeeded()
if !chromeVisible {
bottomChrome.transform = CGAffineTransform(translationX: 0, y: bottomChrome.bounds.height)
for (index, asset) in project.orderedAssets.enumerated() {
variantSegmentedControl.insertSegment(withTitle: asset.kind.title, at: index, animated: false)
}
variantSegmentedControl.selectedSegmentIndex = project.orderedAssets.firstIndex {
$0.kind == activeKind
} ?? 0
setVariantControlsVisible(true)
}
@objc private func tabTapped(_ sender: UIButton) {
guard let kind = TravelAlbumPreviewAssetKind(rawValue: sender.tag),
let node = currentNode,
private func setVariantControlsVisible(_ visible: Bool) {
let visibilityChanged = didConfigureVariantControls && showsVariantControls != visible
didConfigureVariantControls = true
showsVariantControls = visible
variantControlsAnimationGeneration += 1
let animationGeneration = variantControlsAnimationGeneration
let shouldAnimate = visibilityChanged
&& chromeVisible
&& view.window != nil
&& UIView.areAnimationsEnabled
&& !UIAccessibility.isReduceMotionEnabled
view.layoutIfNeeded()
variantControls.isHidden = false
variantSegmentedControl.isHidden = false
highResolutionButton.isHidden = false
variantControlsHeightConstraint?.update(offset: visible ? 56 : 0)
guard shouldAnimate else {
variantControls.alpha = 1
variantControls.transform = .identity
view.layoutIfNeeded()
variantControls.isHidden = !visible
variantSegmentedControl.isHidden = !visible
highResolutionButton.isHidden = !visible
updateHiddenBottomChromePositionIfNeeded()
return
}
if visible {
variantControls.alpha = 0
variantControls.transform = CGAffineTransform(translationX: 0, y: 8)
}
UIView.animate(
withDuration: 0.24,
delay: 0,
options: [.curveEaseInOut, .beginFromCurrentState, .allowUserInteraction],
animations: {
self.variantControls.alpha = visible ? 1 : 0
self.variantControls.transform = visible
? .identity
: CGAffineTransform(translationX: 0, y: 8)
self.view.layoutIfNeeded()
},
completion: { [weak self] finished in
guard let self,
finished,
self.variantControlsAnimationGeneration == animationGeneration
else { return }
self.variantControls.isHidden = !visible
self.variantSegmentedControl.isHidden = !visible
self.highResolutionButton.isHidden = !visible
self.variantControls.alpha = 1
self.variantControls.transform = .identity
self.updateHiddenBottomChromePositionIfNeeded()
}
)
}
private func updateHiddenBottomChromePositionIfNeeded() {
guard !chromeVisible else { return }
bottomChrome.transform = CGAffineTransform(translationX: 0, y: bottomChrome.bounds.height)
}
@objc private func segmentChanged(_ sender: UISegmentedControl) {
guard let project = currentProject,
project.orderedAssets.indices.contains(sender.selectedSegmentIndex)
else { return }
let kind = project.orderedAssets[sender.selectedSegmentIndex].kind
guard let node = currentNode,
currentProject?.asset(for: kind) != nil
else { return }
switch configuration.swipeMode {
@@ -454,6 +581,11 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
dismiss(animated: true)
}
@objc private func highResolutionTapped() {
guard chromeVisible else { return }
toggleChrome()
}
@objc private func aiTapped() {
guard presentedViewController == nil else { return }
guard let project = currentProject else { return }
@@ -661,7 +793,7 @@ final class TravelAlbumPhotoPreviewViewController: UIViewController {
refreshButton.accessibilityValue = isRefreshingProject ? "刷新中" : nil
var configuration = refreshButton.configuration
configuration?.showsActivityIndicator = isRefreshingProject
configuration?.image = isRefreshingProject ? nil : UIImage(systemName: "arrow.clockwise")
configuration?.image = isRefreshingProject ? nil : UIImage(systemName: "arrow.counterclockwise.circle")
configuration?.title = isRefreshingProject ? "刷新中" : "刷新"
refreshButton.configuration = configuration
}
@@ -184,12 +184,13 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
controller.view.frame = CGRect(x: 0, y: 0, width: 390, height: 844)
controller.view.layoutIfNeeded()
let retouchedButton = try XCTUnwrap(
let segmentedControl = try XCTUnwrap(
controller.view.findSubview {
($0 as? UIButton)?.accessibilityLabel == "精修后"
} as? UIButton
$0.accessibilityIdentifier == "travelAlbum.previewVariantSegmentedControl"
} as? UISegmentedControl
)
retouchedButton.sendActions(for: .touchUpInside)
segmentedControl.selectedSegmentIndex = 1
segmentedControl.sendActions(for: .valueChanged)
controller.view.layoutIfNeeded()
let imageView = try XCTUnwrap(
@@ -205,6 +206,148 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
XCTAssertFalse(imageView.constraintsAffectingLayout(for: .vertical).isEmpty)
}
func testPreviewUsesScreenshotChromeAndConstrainedImageViewport() throws {
UIView.setAnimationsEnabled(false)
defer { UIView.setAnimationsEnabled(true) }
let project = TravelAlbumPreviewProject(
originalMaterialId: 1,
assets: [
TravelAlbumPreviewAsset(
id: "original-1",
kind: .original,
fileURL: "https://example.com/original.jpg",
coverURL: "https://example.com/cover.jpg",
fileName: "IMG_0002.jpeg",
fileSize: 2_516_582
),
TravelAlbumPreviewAsset(
id: "retouched-1",
kind: .retouched,
fileURL: "",
coverURL: "",
fileName: "IMG_0002.jpeg",
fileSize: 2_516_582
),
TravelAlbumPreviewAsset(
id: "atmosphere-1",
kind: .atmosphere,
fileURL: "",
coverURL: "",
fileName: "IMG_0002.jpeg",
fileSize: 2_516_582
),
]
)
let controller = TravelAlbumPhotoPreviewViewController(
projects: [project],
totalCount: 10,
startProjectIndex: 0
)
controller.loadViewIfNeeded()
controller.view.frame = CGRect(x: 0, y: 0, width: 390, height: 844)
controller.view.layoutIfNeeded()
let topChrome = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewTopChrome"
}
)
let bottomChrome = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewBottomChrome"
}
)
let collectionView = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewCollectionView"
} as? UICollectionView
)
let highResolutionButton = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewHighResolutionButton"
} as? UIButton
)
let segmentedControl = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewVariantSegmentedControl"
} as? UISegmentedControl
)
let backButton = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewBackButton"
} as? UIButton
)
XCTAssertFalse(controller.prefersStatusBarHidden)
XCTAssertEqual(topChrome.backgroundColor, .black)
XCTAssertEqual(bottomChrome.backgroundColor, .black)
XCTAssertEqual(highResolutionButton.configuration?.title, "查看高清图")
XCTAssertEqual(segmentedControl.numberOfSegments, 3)
XCTAssertEqual(segmentedControl.selectedSegmentIndex, 0)
XCTAssertEqual(backButton.bounds.size, CGSize(width: 44, height: 44))
XCTAssertNil(backButton.configuration?.baseBackgroundColor)
XCTAssertEqual(collectionView.frame.minY, topChrome.frame.maxY, accuracy: 0.5)
XCTAssertEqual(collectionView.frame.maxY, bottomChrome.frame.minY, accuracy: 0.5)
XCTAssertTrue(controller.view.allLabels().contains { $0.text == "IMG_0002.jpeg" })
XCTAssertTrue(controller.view.allLabels().contains { $0.text == "2.4MB" })
XCTAssertTrue(controller.view.allLabels().contains { $0.text == "1/10" })
highResolutionButton.sendActions(for: .touchUpInside)
XCTAssertEqual(topChrome.alpha, 0)
XCTAssertEqual(bottomChrome.alpha, 0)
}
func testPreviewHidesVariantControlsAndHighResolutionButtonWithoutVariants() throws {
let project = TravelAlbumPreviewProject(
originalMaterialId: 1,
assets: [
TravelAlbumPreviewAsset(
id: "original-1",
kind: .original,
fileURL: "https://example.com/original.jpg",
coverURL: "https://example.com/cover.jpg",
fileName: "IMG_0002.jpeg",
fileSize: 2_516_582
),
]
)
let controller = TravelAlbumPhotoPreviewViewController(
projects: [project],
totalCount: 1,
startProjectIndex: 0
)
controller.loadViewIfNeeded()
controller.view.frame = CGRect(x: 0, y: 0, width: 390, height: 844)
controller.view.layoutIfNeeded()
let segmentedControl = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewVariantSegmentedControl"
} as? UISegmentedControl
)
let highResolutionButton = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewHighResolutionButton"
} as? UIButton
)
let collectionView = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewCollectionView"
} as? UICollectionView
)
let bottomChrome = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewBottomChrome"
}
)
XCTAssertTrue(segmentedControl.isHidden)
XCTAssertTrue(highResolutionButton.isHidden)
XCTAssertEqual(bottomChrome.frame.minY - collectionView.frame.maxY, 56, accuracy: 0.5)
}
func testSelectionModeShowsAIRetouchOnLeftAndDeleteOnRight() async throws {
let controller = TravelAlbumDetailViewController(albumId: 0)
controller.loadViewIfNeeded()
@@ -479,10 +622,13 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
controller.loadViewIfNeeded()
controller.view.layoutIfNeeded()
let retouchedButton = try XCTUnwrap(
controller.view.findSubview { ($0 as? UIButton)?.accessibilityLabel == "精修后" } as? UIButton
let segmentedControl = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewVariantSegmentedControl"
} as? UISegmentedControl
)
retouchedButton.sendActions(for: .touchUpInside)
segmentedControl.selectedSegmentIndex = 1
segmentedControl.sendActions(for: .valueChanged)
let aiButton = try XCTUnwrap(
controller.view.findSubview { ($0 as? UIButton)?.accessibilityLabel == "AI修图" } as? UIButton
)
@@ -563,10 +709,13 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
controller.loadViewIfNeeded()
controller.view.frame = CGRect(x: 0, y: 0, width: 390, height: 844)
controller.view.layoutIfNeeded()
let retouchedButton = try XCTUnwrap(
controller.view.findSubview { ($0 as? UIButton)?.accessibilityLabel == "精修后" } as? UIButton
let segmentedControl = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewVariantSegmentedControl"
} as? UISegmentedControl
)
retouchedButton.sendActions(for: .touchUpInside)
segmentedControl.selectedSegmentIndex = 1
segmentedControl.sendActions(for: .valueChanged)
let refreshButton = try XCTUnwrap(
controller.view.findSubview {
$0.accessibilityIdentifier == "travelAlbum.previewRefreshButton"
@@ -575,18 +724,12 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
refreshButton.sendActions(for: .touchUpInside)
await waitUntil { reloadCount == 1 && refreshButton.isEnabled }
XCTAssertTrue(
controller.view.findSubview {
($0 as? UIButton)?.accessibilityLabel == "精修后"
&& $0.accessibilityTraits.contains(.selected)
} != nil
)
XCTAssertEqual(segmentedControl.selectedSegmentIndex, 1)
refreshButton.sendActions(for: .touchUpInside)
await waitUntil { reloadCount == 2 && refreshButton.isEnabled }
XCTAssertNil(
controller.view.findSubview { ($0 as? UIButton)?.accessibilityLabel == "精修后" }
)
XCTAssertTrue(segmentedControl.isHidden)
XCTAssertEqual(segmentedControl.numberOfSegments, 0)
XCTAssertTrue(controller.view.allLabels().contains { $0.text == "原图.jpg" })
}