Files
suixinkan_uikit/suixinkan/Features/TravelAlbum/ViewModels/TravelAlbumAutoRetouchSettingViewModel.swift
lujiuyin 396597a160 feat: 优化自动修图设置与模板网格交互
同页切换修图方式并展开三列模板,复用模板卡片与对比预览,保留草稿和滚动位置,统一卡片与固定底栏样式并补充回归测试。
2026-08-27 17:15:50 +08:00

98 lines
3.4 KiB
Swift

import Foundation
/// 自动修图设置状态,负责加载真实精修模板、单选和配置校验,不直接创建修图任务。
final class TravelAlbumAutoRetouchSettingViewModel {
let scenicId: Int
/// 是否在模板上方展示修图方式;创建页已选择 AI 时只展示模板。
let allowsModeSelection: Bool
private(set) var templates: [TravelAlbumAIRetouchTemplate] = []
private(set) var selectedTemplateId: Int?
private(set) var isEnabled: Bool
private(set) var isLoading = false
private(set) var errorMessage: String?
var onStateChange: (() -> Void)?
/// 创建自动修图配置状态。
init(
scenicId: Int,
configuration: TravelAlbumAutoRetouchConfiguration,
allowsModeSelection: Bool
) {
self.scenicId = scenicId
self.allowsModeSelection = allowsModeSelection
self.isEnabled = configuration.enabled || !allowsModeSelection
self.selectedTemplateId = configuration.refinedTemplateId
}
/// 关闭自动修图不依赖模板加载;开启时必须选择有效模板。
var canConfirm: Bool {
!isEnabled || (!isLoading && pendingConfiguration != nil)
}
/// 当前草稿模板名称,用于固定底部的选择摘要。
var selectedTemplateName: String? {
templates.first { $0.id == selectedTemplateId }?.name
}
/// 当前可提交配置;启用状态必须已经选择服务端模板。
var pendingConfiguration: TravelAlbumAutoRetouchConfiguration? {
if !isEnabled { return .disabled }
guard let selectedTemplateId,
templates.contains(where: { $0.id == selectedTemplateId }) else {
return nil
}
return TravelAlbumAutoRetouchConfiguration(
enabled: true,
refinedTemplateId: selectedTemplateId
)
}
/// 拉取当前景区的真实精修模板。
func loadTemplates(api: any TravelAlbumServing) async {
guard scenicId > 0 else {
errorMessage = "请先选择景区"
notify()
return
}
guard !isLoading else { return }
isLoading = true
errorMessage = nil
notify()
defer {
isLoading = false
notify()
}
do {
let response = try await api.aiRetouchTemplates(scenicId: scenicId)
templates = response.refinedTemplates
if !templates.contains(where: { $0.id == selectedTemplateId }) {
selectedTemplateId = nil
}
if templates.isEmpty { errorMessage = "暂无可用的原图精修模板" }
} catch is CancellationError {
return
} catch {
templates = []
errorMessage = error.localizedDescription.isEmpty ? "模板加载失败" : error.localizedDescription
}
}
/// 切换修图方式,保留本次草稿模板以便再次开启;关闭配置提交时仍不携带模板。
func selectMode(enabled: Bool) {
guard allowsModeSelection else { return }
isEnabled = enabled
notify()
}
/// 选择一个真实精修模板。
func selectTemplate(id: Int) {
guard templates.contains(where: { $0.id == id }) else { return }
isEnabled = true
selectedTemplateId = id
notify()
}
private func notify() { onStateChange?() }
}