diff --git a/suixinkan/UI/TravelAlbum/TravelAlbumPhotoPreviewViewController.swift b/suixinkan/UI/TravelAlbum/TravelAlbumPhotoPreviewViewController.swift index 73fce96..d11ea6e 100644 --- a/suixinkan/UI/TravelAlbum/TravelAlbumPhotoPreviewViewController.swift +++ b/suixinkan/UI/TravelAlbum/TravelAlbumPhotoPreviewViewController.swift @@ -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 } diff --git a/suixinkanTests/TravelAlbumDetailViewControllerTests.swift b/suixinkanTests/TravelAlbumDetailViewControllerTests.swift index 0f968a6..6bf3bfb 100644 --- a/suixinkanTests/TravelAlbumDetailViewControllerTests.swift +++ b/suixinkanTests/TravelAlbumDetailViewControllerTests.swift @@ -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" }) }