|
@@ -0,0 +1,341 @@
|
|
|
+//
|
|
|
+// TSAIRemovePhotoBgVC.swift
|
|
|
+// TSLiveWallpaper
|
|
|
+//
|
|
|
+// Created by 100Years on 2025/7/21.
|
|
|
+//
|
|
|
+import Kingfisher
|
|
|
+class TSAIRemovePhotoBgVC: TSBaseVC {
|
|
|
+
|
|
|
+
|
|
|
+ var originalImage:UIImage
|
|
|
+ init(image: UIImage) {
|
|
|
+ self.originalImage = image
|
|
|
+ super.init()
|
|
|
+ }
|
|
|
+
|
|
|
+ @MainActor required init?(coder: NSCoder) {
|
|
|
+ fatalError("init(coder:) has not been implemented")
|
|
|
+ }
|
|
|
+ lazy var photoPickerManager: TSPhotoPickerManager = TSPhotoPickerManager(viewController: self)
|
|
|
+ var isSavePhotoMark:Bool = false
|
|
|
+ var isNeedSavePhoto:Bool {
|
|
|
+ if isSavePhotoMark == false,let _ = infoModel {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ var infoModel:TSActionInfoModel?{
|
|
|
+ didSet{
|
|
|
+ updateImageView()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var operation:TSGenerateBaseOperation?
|
|
|
+ var uuidString:String = UUID().uuidString
|
|
|
+ var progressState = TSProgressState.none
|
|
|
+
|
|
|
+ lazy var shareBtn: TSVerticalButton = {
|
|
|
+ let shareBtn = TSVerticalButton()
|
|
|
+ shareBtn.setUpButton(title: "Share".localized,
|
|
|
+ image: .share,
|
|
|
+ font: .font(name:.ZillaSlab,size: 14,weight: .medium),
|
|
|
+ titleColor: .white.withAlphaComponent(0.8),
|
|
|
+ autoMirrored: false){ [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ clickShare()
|
|
|
+ }
|
|
|
+ shareBtn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
|
|
|
+ shareBtn.titleLabel?.layer.shadowColor = UIColor.black.cgColor
|
|
|
+ shareBtn.titleLabel?.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
|
+ shareBtn.titleLabel?.layer.shadowRadius = 3
|
|
|
+ shareBtn.titleLabel?.layer.shadowOpacity = 0.4
|
|
|
+ shareBtn.titleLabel?.layer.masksToBounds = false
|
|
|
+ return shareBtn
|
|
|
+ }()
|
|
|
+ lazy var saveBtn: UIButton = {
|
|
|
+ let saveBtn = kCreateNormalSubmitBtn(title: "Save".localized) { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ clickSaveBtn()
|
|
|
+ }
|
|
|
+ kSetBtnVipIcon(btn: saveBtn, show: true)
|
|
|
+ return saveBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+ lazy var removeView: TSAIPhotoRemoveBgView = {
|
|
|
+ let removeView = TSAIPhotoRemoveBgView(targetVC: self)
|
|
|
+ removeView.setFrontImage(image: originalImage)
|
|
|
+ return removeView
|
|
|
+ }()
|
|
|
+
|
|
|
+ lazy var generateInView : TSGeneratorView = {
|
|
|
+ let generateInView = TSGeneratorView()
|
|
|
+ generateInView.isUploadImage = false
|
|
|
+ generateInView.backgroundColor = .black.withAlphaComponent(0.95)
|
|
|
+ generateInView.animationView.setText(time: String(format: "~ %d mins".localized, 1), info: "Lots of people are processing images right now, so this might take a bit.".localized)
|
|
|
+ generateInView.clickErrorBlock = { [weak self] style in
|
|
|
+ guard let self = self else { return }
|
|
|
+
|
|
|
+ switch style {
|
|
|
+ case .netWorkError:
|
|
|
+ clickRegenerateBtn()
|
|
|
+ default:
|
|
|
+ self.dismiss(animated: false, completion: nil)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+// generateInView.clickBackstageBlock = { [weak self] in
|
|
|
+// guard let self = self else { return }
|
|
|
+// clickBackstageBtn()
|
|
|
+// }
|
|
|
+ generateInView.clickCloseBlock = { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ closePage()
|
|
|
+ }
|
|
|
+ return generateInView
|
|
|
+ }()
|
|
|
+
|
|
|
+ //重新生成
|
|
|
+ @objc func clickRegenerateBtn(){
|
|
|
+ if kPurchaseBusiness.kJudgeVipFreeType(vipFreeNumType: .generalRemoveBg){ return }//判断 vip
|
|
|
+ generatorOperation()
|
|
|
+ }
|
|
|
+ func updateImageView(){
|
|
|
+ guard let infoModel = self.infoModel else { return }
|
|
|
+ removeView.setFrontImageURLString(urlString: infoModel.response.resultUrl)
|
|
|
+ }
|
|
|
+
|
|
|
+ func closePage() {
|
|
|
+
|
|
|
+ if progressState.isResult {
|
|
|
+ if isNeedSavePhoto{
|
|
|
+ TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
|
|
|
+ message: "You haven't saved the photo yet. Are you sure to quit?".localized,
|
|
|
+ messageColor: .white,
|
|
|
+ messageFont: .systemFont(ofSize: 16),
|
|
|
+
|
|
|
+ cancelTitle: "Quit".localized,
|
|
|
+ cancelColor: .white,
|
|
|
+
|
|
|
+ confirmTitle: "Save".localized,
|
|
|
+ confirmColor: .themeColor,
|
|
|
+
|
|
|
+ cancelAction: { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ print("用户点击了Leave")
|
|
|
+ cancelDidmiss()
|
|
|
+ },
|
|
|
+ confirmAction: { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ print("用户点击了Stay")
|
|
|
+ clickSaveBtn()
|
|
|
+ }
|
|
|
+ ))
|
|
|
+ }else{
|
|
|
+ cancelDidmiss()
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
|
|
|
+ message: "As you leave, your task will be interrupted and no result.".localized,
|
|
|
+ messageColor: .white,
|
|
|
+ messageFont: .systemFont(ofSize: 16),
|
|
|
+
|
|
|
+ cancelTitle: "Leave".localized,
|
|
|
+ cancelColor: .white,
|
|
|
+
|
|
|
+ confirmTitle: "Wait".localized,
|
|
|
+ confirmColor: .themeColor,
|
|
|
+
|
|
|
+ cancelAction: { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ print("用户点击了Leave")
|
|
|
+ if let model = infoModel{
|
|
|
+ TSRMShared.aiListDB.deleteListModel(id: model.id)
|
|
|
+ NotificationCenter.default.post(name: .kAIPhotoDataChanged, object: nil)
|
|
|
+ }
|
|
|
+ cancelDidmiss()
|
|
|
+ },
|
|
|
+ confirmAction: {
|
|
|
+ print("用户点击了Stay")
|
|
|
+ }
|
|
|
+ ))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func cancelDidmiss(){
|
|
|
+ operation?.cancel()
|
|
|
+ self.dismiss(animated: true, completion: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ override func createView() {
|
|
|
+ setPageTitle("Remove Background".localized)
|
|
|
+
|
|
|
+ _ = setNavigationItem("", imageName: "replace_photo", direction: .right, action: #selector(clickNavRight))
|
|
|
+ contentView.addSubview(removeView)
|
|
|
+ removeView.snp.makeConstraints { make in
|
|
|
+ make.edges.equalToSuperview()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ let bottomBtnTop:CGFloat = -8-k_Height_safeAreaInsetsBottom()
|
|
|
+ contentView.addSubview(shareBtn)
|
|
|
+ shareBtn.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(16)
|
|
|
+ make.width.equalTo(shareBtn.intrinsicContentSize.width)
|
|
|
+ make.height.equalTo(48)
|
|
|
+ make.bottom.equalTo(bottomBtnTop)
|
|
|
+ }
|
|
|
+
|
|
|
+ contentView.addSubview(saveBtn)
|
|
|
+ saveBtn.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(shareBtn.snp.trailing).offset(40)
|
|
|
+ make.trailing.equalTo(-16.0)
|
|
|
+ make.height.equalTo(48)
|
|
|
+ make.bottom.equalTo(bottomBtnTop)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ view.addSubview(generateInView)
|
|
|
+ generateInView.snp.makeConstraints { make in
|
|
|
+ make.edges.equalToSuperview()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ override func dealThings() {
|
|
|
+ self.uuidString = UUID().uuidString
|
|
|
+ generatorOperation()
|
|
|
+ }
|
|
|
+
|
|
|
+ func generatorOperation() {
|
|
|
+ generatorNew()
|
|
|
+ }
|
|
|
+}
|
|
|
+extension TSAIRemovePhotoBgVC {
|
|
|
+ //分享功能
|
|
|
+ @objc func clickShare(){
|
|
|
+ if kJudgeVip(externalBool: true, vc: self){ return }
|
|
|
+ removeView.compositeImages { [weak self] image in
|
|
|
+ guard let self = self else { return }
|
|
|
+ if let image = image {
|
|
|
+ kShareContent(target: self, anyData: image)
|
|
|
+ guard let infoModel = self.infoModel else { return }
|
|
|
+
|
|
|
+ if let resultUrl = self.infoModel?.response.resultUrl,
|
|
|
+ let url = URL(string: resultUrl){
|
|
|
+ ImageCache.default.store(image, forKey: url.cacheKey)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @objc func clickNavRight() {
|
|
|
+ if kPurchaseBusiness.kJudgeVipFreeType(vipFreeNumType: .generalRemoveBg){ return }//判断 vip
|
|
|
+ photoPickerManager.pickPhoto(maxSelected: 1) { [weak self] images in
|
|
|
+ guard let self = self else { return }
|
|
|
+ if let image = images.first {
|
|
|
+ originalImage = image
|
|
|
+ removeView.setFrontImage(image: originalImage)
|
|
|
+ }
|
|
|
+ self.photoPickerManager.dismissPageVC()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //保存功能
|
|
|
+ @objc func clickSaveBtn(){
|
|
|
+ if kJudgeVip(externalBool: true, vc: self){ return }
|
|
|
+ removeView.compositeImages { [weak self] image in
|
|
|
+ if let image = image {
|
|
|
+ PhotoManagerShared.saveImageToAlbum(image) { [weak self] success, error in
|
|
|
+ guard let self = self else { return }
|
|
|
+ if success {
|
|
|
+// isSavePhotoMark = true
|
|
|
+ kSaveSuccesswShared.show(atView:self.view)
|
|
|
+
|
|
|
+ if let resultUrl = self.infoModel?.response.resultUrl,
|
|
|
+ let url = URL(string: resultUrl){
|
|
|
+ ImageCache.default.store(image, forKey: url.cacheKey)
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ debugPrint(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+extension TSAIRemovePhotoBgVC{
|
|
|
+
|
|
|
+ func generatorNew() {
|
|
|
+ let operation:TSGenerateBasePhotoOperation = TSGenerateBasePhotoOperationQueue.shared.creatOperation(uuid: self.uuidString)
|
|
|
+ self.operation = operation
|
|
|
+ operation.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self] (state,model) in
|
|
|
+ guard let self = self else { return }
|
|
|
+ self.upDateView(state: state, model: model)
|
|
|
+ }.store(in: &cancellable)
|
|
|
+
|
|
|
+
|
|
|
+ let generatorModel = TSAIListPhotoGeneratorModel(upLoadImage: originalImage, generatorStyle: .removeBg)
|
|
|
+
|
|
|
+ operation.uploadImage(generateStyleModel: generatorModel) { [weak self] actionInfoModel in
|
|
|
+ guard let self = self else { return }
|
|
|
+ guard let oldModel = actionInfoModel else {return}
|
|
|
+ generatorCreatRing(oldModel: oldModel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func generatorCreatRing(oldModel:TSActionInfoModel) {
|
|
|
+ let operation:TSGenerateBasePhotoOperation = TSGenerateBasePhotoOperationQueue.shared.creatOperation(uuid: self.uuidString)
|
|
|
+ self.operation = operation
|
|
|
+ operation.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self] (state,model) in
|
|
|
+ guard let self = self else { return }
|
|
|
+ self.upDateView(state: state, model: model)
|
|
|
+ }.store(in: &cancellable)
|
|
|
+
|
|
|
+ operation.creatImage(oldModel: oldModel){ [weak self] success in
|
|
|
+ guard let self = self else { return }
|
|
|
+ if success {
|
|
|
+ generateInView.setBackgroundGenerateBtnHidden(true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+extension TSAIRemovePhotoBgVC {
|
|
|
+ func upDateView(state:TSProgressState,model:TSActionInfoModel?){
|
|
|
+ progressState = state
|
|
|
+ switch state {
|
|
|
+ case .failed(let errorStr,let code):
|
|
|
+ showError(text: errorStr,code:code)
|
|
|
+ case .success:
|
|
|
+ if let model = model {
|
|
|
+ showSuccess(model: model)
|
|
|
+ }else{
|
|
|
+ showError(text: "")
|
|
|
+ }
|
|
|
+ case .progressString(let string):
|
|
|
+ showProgress(text: string)
|
|
|
+ default:
|
|
|
+ showLoading()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func showProgress(text:String) {
|
|
|
+ generateInView.updateShowProgress(text: text)
|
|
|
+ }
|
|
|
+
|
|
|
+ func showLoading(){
|
|
|
+ generateInView.updateShowLoading(text: "Processing".localized + " " + kPercentlocalized(0))
|
|
|
+ }
|
|
|
+
|
|
|
+ func showError(text:String,code:Int = 0){
|
|
|
+ generateInView.updateShowError(text: text,code: code)
|
|
|
+ }
|
|
|
+
|
|
|
+ func showSuccess(model:TSActionInfoModel){
|
|
|
+ generateInView.updateShowSuccess()
|
|
|
+ infoModel = model
|
|
|
+ if let model = infoModel {
|
|
|
+// complete(model)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|