TSAIGenerateVC.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. //
  2. // TSAIGenerateVC.swift
  3. // AIEmoji
  4. //
  5. // Created by 100Years on 2025/6/24.
  6. //
  7. class TSAIGenerateVC: TSAIGenerateBaseVC {
  8. var reloadViewBlock: (() -> Void)?
  9. var changeImageBlock: ((UIImage) -> Void)?
  10. var progressState = TSProgressState.none
  11. var isSavePhotoMark: Bool = false
  12. var isNeedSavePhoto: Bool {
  13. if isSavePhotoMark == false, let _ = infoModel {
  14. return true
  15. }
  16. return false
  17. }
  18. var uuidString: String = UUID().uuidString
  19. var operation: TSGenerateBaseOperation?
  20. lazy var photoPickerManager: TSPhotoPickerManager = {
  21. let photoPickerManager = TSPhotoPickerManager(viewController: self)
  22. return photoPickerManager
  23. }()
  24. lazy var generateInView: TSGeneratorView = {
  25. let generateInView = TSGeneratorView()
  26. // if generatorModel.advance {
  27. // generateInView.animationView.setText(time: String(format: "~ %d min".localized, 2), info: "Lots of people are creating images right now, so this might take a bit.".localized)
  28. // }else{
  29. // generateInView.animationView.setText(time: String(format: "~ %d seconds".localized, 20), info: "")
  30. // }
  31. let videoCategorys : [TSFuncStyle] = [.photoLive,.videoV2,.textToVideo,.pictureToVideo]
  32. if videoCategorys.contains(generatorModel.generatorStyle) {
  33. generateInView.animationView.setText(time: String(format: "~ %d min".localized, 2), info: "Lots of people are creating videos right now, so this might take a bit.".localized)
  34. }else{
  35. generateInView.animationView.setText(time: String(format: "~ %d min".localized, 2), info: "Lots of people are creating images right now, so this might take a bit.".localized)
  36. }
  37. generateInView.clickBackstageBlock = { [weak self] in
  38. guard let self = self else { return }
  39. clickBackstageBtn()
  40. }
  41. generateInView.clickErrorBlock = { [weak self] style in
  42. guard let self = self else { return }
  43. switch style {
  44. case .netWorkError:
  45. clickTryAgainBtn()
  46. case .sensitiveError:
  47. pickSinglePhoto()
  48. case .generateToMax:
  49. clickTryAgainBtn()
  50. default:
  51. self.dismiss(animated: false, completion: nil)
  52. break
  53. }
  54. }
  55. return generateInView
  56. }()
  57. override func createView() {
  58. view.insertSubview(generateInView, at: 0)
  59. generateInView.snp.makeConstraints { make in
  60. make.edges.equalToSuperview()
  61. }
  62. super.createView()
  63. contentView.isHidden = true
  64. }
  65. override func closePage() {
  66. if progressState.isResult {
  67. if isNeedSavePhoto {
  68. TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
  69. message: "You haven't saved the photo yet. Are you sure to quit?".localized,
  70. messageColor: .white,
  71. messageFont: .systemFont(ofSize: 16),
  72. cancelTitle: "Quit".localized,
  73. cancelColor: .white,
  74. confirmTitle: "Save".localized,
  75. confirmColor: .themeColor,
  76. cancelAction: { [weak self] in
  77. guard let self = self else { return }
  78. print("用户点击了Leave")
  79. cancelDidmiss()
  80. },
  81. confirmAction: { [weak self] in
  82. guard let self = self else { return }
  83. print("用户点击了Stay")
  84. clickSaveBtn()
  85. }
  86. ))
  87. } else {
  88. cancelDidmiss()
  89. }
  90. } else {
  91. TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
  92. message: "As you leave, your generation will be interrupted and no result.".localized,
  93. messageColor: .white,
  94. messageFont: .systemFont(ofSize: 16),
  95. cancelTitle: "Leave".localized,
  96. cancelColor: .white,
  97. confirmTitle: "Wait".localized,
  98. confirmColor: .themeColor,
  99. cancelAction: { [weak self] in
  100. guard let self = self else { return }
  101. print("用户点击了Leave")
  102. if let model = infoModel {
  103. TSRMShared.aiGenerateDB.deleteListModel(uuid: model.uuid)
  104. NotificationCenter.default.post(name: .kAIPhotoDataChanged, object: nil)
  105. }
  106. cancelDidmiss()
  107. },
  108. confirmAction: {
  109. print("用户点击了Stay")
  110. }
  111. ))
  112. }
  113. }
  114. func cancelDidmiss() {
  115. operation?.cancel()
  116. dismiss(animated: true, completion: nil)
  117. }
  118. // 重试
  119. @objc override func clickTryAgainBtn() {
  120. clickRegenerateBtn()
  121. }
  122. // 后台生成
  123. @objc func clickBackstageBtn() {
  124. operation?.backstageGeneration()
  125. NotificationCenter.default.post(name: .kAIPhotoDataChanged, object: nil)
  126. NotificationCenter.default.post(name: .kAIComeInBackstage, object: nil)
  127. dismiss(animated: true, completion: nil)
  128. }
  129. // 重新生成
  130. @objc override func clickRegenerateBtn() {
  131. // 判断 vip
  132. // if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .aiGenerate) == false, vc: self) { return }
  133. if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: generatorModel.generatorStyle.vipFreeNumType) == false, vc: self) { return }
  134. infoModel?.actionStatus = .failed // 状态设为失败,走generatorCreat
  135. uuidString = UUID().uuidString // 设置新的uuid,新的储存数据
  136. generatorOperation() // 开始生成
  137. }
  138. // 保存功能
  139. // @objc override func clickSaveBtn(){
  140. // if let image = getSuccessImage() {
  141. // PhotoManagerShared.saveImageToAlbum(image) { success, error in
  142. // if success {
  143. // kSaveSuccesswShared.show(atView:self.view)
  144. //
  145. // self.isSavePhotoMark = true
  146. // }else{
  147. // debugPrint(error)
  148. // }
  149. // }
  150. // }
  151. // }
  152. // 保存功能
  153. @objc override func clickSaveBtn() {
  154. isSavePhotoMark = true
  155. if kJudgeVip(externalBool: true, vc: self) {
  156. return
  157. }
  158. guard let currentModel = infoModel else { return }
  159. let response = currentModel.response
  160. let urlString = response.resultUrl
  161. if currentModel.isVideo {
  162. TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
  163. if let url = url {
  164. PhotoManagerShared.saveVideoToAlbum(videoURL: url) { success, error in
  165. if success {
  166. kSaveSuccesswShared.show(atView: self.view)
  167. } else {
  168. debugPrint(error)
  169. }
  170. }
  171. }
  172. }
  173. } else {
  174. TSImageStoreTool.downloadImageWithProgress(urlString: urlString) { image in
  175. if let image = image {
  176. PhotoManagerShared.saveImageToAlbum(image) { success, error in
  177. if success {
  178. kSaveSuccesswShared.show(atView: self.view)
  179. } else {
  180. debugPrint(error)
  181. }
  182. }
  183. } else { // 如果服务器取不到,直接保存当前显示的图片
  184. if let currentImage = self.getSuccessImage() {
  185. PhotoManagerShared.saveImageToAlbum(currentImage) { success, error in
  186. if success {
  187. kSaveSuccesswShared.show(atView: self.view)
  188. } else {
  189. debugPrint(error)
  190. }
  191. }
  192. }
  193. }
  194. }
  195. }
  196. }
  197. // override func clickShare() {
  198. // guard let image = getSuccessImage() else { return }
  199. // kShareContent(target: self, anyData: image)
  200. // }
  201. override func clickShare() {
  202. isSavePhotoMark = true
  203. if kJudgeVip(externalBool: true, vc: self) {
  204. return
  205. }
  206. guard let currentModel = infoModel else { return }
  207. let response = currentModel.response
  208. let urlString = response.resultUrl
  209. if currentModel.isVideo {
  210. TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
  211. if let url = url {
  212. kShareContent(target: self, anyData: url)
  213. }
  214. }
  215. } else {
  216. TSImageStoreTool.downloadImageWithProgress(urlString: urlString) { image in
  217. if let image = image {
  218. kShareContent(target: self, anyData: image)
  219. } else { // 如果服务器取不到,直接保存当前显示的图片
  220. if let currentImage = self.getSuccessImage() {
  221. kShareContent(target: self, anyData: currentImage)
  222. }
  223. }
  224. }
  225. }
  226. }
  227. override func dealThings() {
  228. uuidString = UUID().uuidString
  229. generatorOperation()
  230. }
  231. func generatorOperation() {
  232. if let model = infoModel {
  233. if model.actionStatus == .failed {
  234. generatorCreat(oldModel: model)
  235. } else if model.response.resultUrl.count > 0 {
  236. upDateView(state: .success(model), model: model)
  237. return
  238. }
  239. } else {
  240. generatorNew()
  241. }
  242. }
  243. }
  244. extension TSAIGenerateVC {
  245. func generatorNew() {
  246. let operation: TSGenerateBasePhotoOperation = TSGenerateBasePhotoOperationQueue.shared.creatOperation(uuid: uuidString)
  247. self.operation = operation
  248. operation.$stateDatauPblished.receive(on: DispatchQueue.main).sink { [weak self] state, model in
  249. guard let self = self else { return }
  250. self.upDateView(state: state, model: model)
  251. }.store(in: &cancellable)
  252. if generatorModel.generatorStyle == .textToVideo {
  253. guard let actionInfoModel = operation.createActionInfoModel(generateStyleModel: generatorModel) else { return }
  254. generatorCreat(oldModel: actionInfoModel)
  255. } else {
  256. operation.uploadImage(generateStyleModel: generatorModel) { [weak self] actionInfoModel in
  257. guard let self = self else { return }
  258. guard let oldModel = actionInfoModel else { return }
  259. generatorCreat(oldModel: oldModel)
  260. }
  261. }
  262. }
  263. func generatorCreat(oldModel: TSActionInfoModel) {
  264. let operation: TSGenerateBasePhotoOperation = TSGenerateBasePhotoOperationQueue.shared.creatOperation(uuid: uuidString)
  265. self.operation = operation
  266. operation.$stateDatauPblished.receive(on: DispatchQueue.main).sink { [weak self] state, model in
  267. guard let self = self else { return }
  268. self.upDateView(state: state, model: model)
  269. }.store(in: &cancellable)
  270. operation.generateStyleModel = generatorModel
  271. operation.creatImage(oldModel: oldModel) { [weak self] success in
  272. guard let self = self else { return }
  273. if success {
  274. generateInView.setBackgroundGenerateBtnHidden(false)
  275. }
  276. }
  277. }
  278. }
  279. extension TSAIGenerateVC {
  280. func pickSinglePhoto() {
  281. photoPickerManager.pickCustomSinglePhoto { [weak self] image, errorString in
  282. guard let self = self else { return }
  283. if let errorString = errorString {
  284. TSToastShared.showToast(text: errorString)
  285. } else {
  286. if let image = image {
  287. changeImageBlock?(image)
  288. generatorModel.upLoadImage = image
  289. generatorModel.upLoadImageUrl = nil
  290. generatorNew()
  291. }
  292. }
  293. kDelayMainShort {
  294. self.photoPickerManager.dismissPageVC()
  295. }
  296. }
  297. }
  298. func getSuccessImage() -> UIImage? {
  299. if let image = netWorkImageView.image {
  300. return image.pngImage
  301. }
  302. return nil
  303. }
  304. }
  305. extension TSAIGenerateVC {
  306. func upDateView(state: TSProgressState, model: TSActionInfoModel?) {
  307. progressState = state
  308. switch state {
  309. case let .failed(errorStr, code):
  310. if handleGenerateToMax(code: code,completion: { [weak self] in
  311. guard let self = self else { return }
  312. self.showError(text: errorStr, code: code)
  313. }){}else {
  314. showError(text: errorStr, code: code)
  315. }
  316. case .success:
  317. if let model = model {
  318. showSuccess(model: model)
  319. } else {
  320. showError(text: "")
  321. }
  322. case let .progressString(string):
  323. showProgress(text: string)
  324. case .none:
  325. break
  326. default:
  327. showLoading()
  328. }
  329. }
  330. func showProgress(text: String) {
  331. generateInView.updateShowProgress(text: text)
  332. contentView.isHidden = true
  333. }
  334. func showLoading() {
  335. generateInView.updateShowLoading(text: "Generating".localized + " " + kPercentlocalized(0))
  336. contentView.isHidden = true
  337. }
  338. func showError(text: String, code: Int = 0) {
  339. generateInView.updateShowError(text: text, code: code)
  340. contentView.isHidden = true
  341. xBtn.isHidden = false
  342. }
  343. func showSuccess(model: TSActionInfoModel) {
  344. generateInView.updateShowSuccess()
  345. contentView.isHidden = false
  346. xBtn.isHidden = false
  347. switchOriginalPictureBtn.isHidden = isHiddenSwitch
  348. infoModel = model
  349. if let model = infoModel {
  350. model.request.inputText = generatorModel.inputText
  351. complete(model)
  352. }
  353. kFirstSaveRateAction()
  354. }
  355. }
  356. extension TSAIGenerateVC {
  357. func handleGenerateToMax(code:Int,completion: (() -> Void)? = nil) -> Bool {
  358. //如果是vip次数超限,则主动触发,让 vc去谈起购买次数的弹窗
  359. let style = TSNetWorkCode.getGeneratorStyle(code: code)
  360. if style == .generateToMax{
  361. kPresentModalVC(target: self, modelVC: TSPurchaseVideoTimesVC(isShowAlertModel: true),transitionStyle:.crossDissolve,completion: completion)
  362. return true
  363. }
  364. return false
  365. }
  366. }