feat: 优化 AI 修图模板选择页面

This commit is contained in:
2026-08-13 15:16:03 +08:00
parent 109ec3dad0
commit 7b9e630838
6 changed files with 35 additions and 25 deletions
@@ -0,0 +1,13 @@
{
"images" : [
{
"filename" : "ai_retouch_template_placeholder.png",
"idiom" : "universal",
"scale" : "1x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -66,12 +66,9 @@ final class TravelAlbumAIRetouchTemplateViewModel {
return false return false
} }
/// 首次修图页按实际展示分组生成的规则说明。 /// 首次修图页固定展示的氛围感与封面生成规则说明。
var initialTipsText: String { var initialTipsText: String {
if visibleCategories.contains(.cover) { "Tips:氛围感修图为选填,可横向选择一种样式;选中后每张照片会额外生成1个独立结果,第一张照片仍另生成封面。"
return "每张照片生成精修结果,氛围感可选;本次可免费生成 1 张封面"
}
return "每张照片生成精修结果,氛围感可选"
} }
/// 当前分组是否为选填。 /// 当前分组是否为选填。
@@ -583,6 +583,7 @@ final class TravelAlbumAIRetouchTemplateCell: UICollectionViewCell {
previewImageView.contentMode = .scaleAspectFill previewImageView.contentMode = .scaleAspectFill
previewImageView.clipsToBounds = true previewImageView.clipsToBounds = true
previewImageView.backgroundColor = UIColor(hex: 0xEDF2F8) previewImageView.backgroundColor = UIColor(hex: 0xEDF2F8)
previewImageView.accessibilityIdentifier = "travelAlbum.aiRetouchTemplateImage"
nameLabel.font = .systemFont(ofSize: 13, weight: .semibold) nameLabel.font = .systemFont(ofSize: 13, weight: .semibold)
nameLabel.textColor = AIRetouchTemplateStyle.textPrimary nameLabel.textColor = AIRetouchTemplateStyle.textPrimary
nameLabel.textAlignment = .center nameLabel.textAlignment = .center
@@ -595,12 +596,12 @@ final class TravelAlbumAIRetouchTemplateCell: UICollectionViewCell {
previewConfiguration.title = "预览" previewConfiguration.title = "预览"
previewConfiguration.baseForegroundColor = .white previewConfiguration.baseForegroundColor = .white
previewConfiguration.baseBackgroundColor = UIColor.black.withAlphaComponent(0.58) previewConfiguration.baseBackgroundColor = UIColor.black.withAlphaComponent(0.58)
previewConfiguration.background.cornerRadius = 15 previewConfiguration.background.cornerRadius = 14
previewConfiguration.contentInsets = .zero previewConfiguration.contentInsets = .zero
previewConfiguration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { previewConfiguration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
attributes in attributes in
var attributes = attributes var attributes = attributes
attributes.font = .systemFont(ofSize: 13, weight: .regular) attributes.font = .systemFont(ofSize: 12, weight: .regular)
return attributes return attributes
} }
previewButton.configuration = previewConfiguration previewButton.configuration = previewConfiguration
@@ -625,9 +626,9 @@ final class TravelAlbumAIRetouchTemplateCell: UICollectionViewCell {
make.size.equalTo(22) make.size.equalTo(22)
} }
previewButton.snp.makeConstraints { make in previewButton.snp.makeConstraints { make in
make.trailing.bottom.equalTo(previewImageView).inset(7) make.trailing.bottom.equalTo(previewImageView).inset(4)
make.width.equalTo(54) make.width.equalTo(48)
make.height.equalTo(30) make.height.equalTo(28)
} }
} }
@@ -646,19 +647,16 @@ final class TravelAlbumAIRetouchTemplateCell: UICollectionViewCell {
/// 更新模板内容与选中状态。 /// 更新模板内容与选中状态。
func apply(template: TravelAlbumAIRetouchTemplate, selected: Bool) { func apply(template: TravelAlbumAIRetouchTemplate, selected: Bool) {
nameLabel.text = template.name nameLabel.text = template.name
let placeholder = UIImage(named: "ai_retouch_template_placeholder")
if let url = URL(string: template.previewURL), !template.previewURL.isEmpty { if let url = URL(string: template.previewURL), !template.previewURL.isEmpty {
previewImageView.contentMode = .scaleAspectFill previewImageView.contentMode = .scaleAspectFill
previewImageView.kf.setImage( previewImageView.kf.setImage(
with: url, with: url,
placeholder: UIImage(systemName: "photo")?.withTintColor( placeholder: placeholder
AIRetouchTemplateStyle.textSecondary,
renderingMode: .alwaysOriginal
)
) )
} else { } else {
previewImageView.image = UIImage(systemName: "photo") previewImageView.image = placeholder
previewImageView.tintColor = AIRetouchTemplateStyle.textSecondary previewImageView.contentMode = .scaleAspectFill
previewImageView.contentMode = .scaleAspectFit
} }
contentView.layer.borderColor = ( contentView.layer.borderColor = (
selected ? AIRetouchTemplateStyle.primary : AIRetouchTemplateStyle.border selected ? AIRetouchTemplateStyle.primary : AIRetouchTemplateStyle.border
@@ -680,7 +678,7 @@ final class TravelAlbumAIRetouchTemplateCell: UICollectionViewCell {
/// 扩大模板预览按钮的触摸区域,同时保持截图中的胶囊尺寸。 /// 扩大模板预览按钮的触摸区域,同时保持截图中的胶囊尺寸。
private final class AIRetouchTemplatePreviewButton: UIButton { private final class AIRetouchTemplatePreviewButton: UIButton {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
bounds.insetBy(dx: -6, dy: -6).contains(point) bounds.insetBy(dx: -8, dy: -8).contains(point)
} }
} }
@@ -1009,17 +1007,14 @@ final class TravelAlbumAIRetouchTemplatePreviewViewController: UIViewController
} }
private func loadPreview() { private func loadPreview() {
let placeholder = UIImage(named: "ai_retouch_template_placeholder")
guard let url = URL(string: template.previewURL), !template.previewURL.isEmpty else { guard let url = URL(string: template.previewURL), !template.previewURL.isEmpty else {
imageView.image = UIImage(systemName: "photo") imageView.image = placeholder
imageView.tintColor = UIColor.white.withAlphaComponent(0.45)
return return
} }
imageView.kf.setImage( imageView.kf.setImage(
with: url, with: url,
placeholder: UIImage(systemName: "photo")?.withTintColor( placeholder: placeholder
UIColor.white.withAlphaComponent(0.45),
renderingMode: .alwaysOriginal
)
) )
} }
@@ -25,7 +25,7 @@ final class TravelAlbumAIRetouchTemplateViewModelTests: XCTestCase {
XCTAssertTrue(viewModel.shouldShowInitialTips) XCTAssertTrue(viewModel.shouldShowInitialTips)
XCTAssertEqual( XCTAssertEqual(
viewModel.initialTipsText, viewModel.initialTipsText,
"每张照片生成精修结果,氛围感可选;本次可免费生成 1 张封面" "Tips:氛围感修图为选填,可横向选择一种样式;选中后每张照片会额外生成1个独立结果,第一张照片仍另生成封面。"
) )
XCTAssertEqual(viewModel.visibleCategories, [.refined, .atmosphere, .cover]) XCTAssertEqual(viewModel.visibleCategories, [.refined, .atmosphere, .cover])
XCTAssertEqual(viewModel.selectedRefinedTemplateId, 11) XCTAssertEqual(viewModel.selectedRefinedTemplateId, 11)
@@ -572,8 +572,13 @@ final class TravelAlbumDetailViewControllerTests: XCTestCase {
let previewButton = cell.findSubview { let previewButton = cell.findSubview {
$0.accessibilityIdentifier == "travelAlbum.aiRetouchTemplatePreviewButton" $0.accessibilityIdentifier == "travelAlbum.aiRetouchTemplatePreviewButton"
} as? UIButton } as? UIButton
let previewImageView = cell.findSubview {
$0.accessibilityIdentifier == "travelAlbum.aiRetouchTemplateImage"
} as? UIImageView
previewButton?.sendActions(for: .touchUpInside) previewButton?.sendActions(for: .touchUpInside)
XCTAssertNotNil(UIImage(named: "ai_retouch_template_placeholder"))
XCTAssertNotNil(previewImageView?.image)
XCTAssertEqual(cell.contentView.layer.borderWidth, 2) XCTAssertEqual(cell.contentView.layer.borderWidth, 2)
XCTAssertTrue(cell.accessibilityTraits.contains(.selected)) XCTAssertTrue(cell.accessibilityTraits.contains(.selected))
XCTAssertEqual(cell.accessibilityValue, "已选择") XCTAssertEqual(cell.accessibilityValue, "已选择")