Browse Source

文生图开发完毕

100Years 1 month ago
parent
commit
f14c7a6fdc
21 changed files with 524 additions and 66 deletions
  1. 16 0
      AIEmoji.xcodeproj/project.pbxproj
  2. 22 0
      AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/Contents.json
  3. BIN
      AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/refresh_gary@2x.png
  4. BIN
      AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/refresh_gary@3x.png
  5. 63 0
      AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseCell.swift
  6. 207 0
      AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift
  7. 0 2
      AIEmoji/Business/General/TSBottomAlertVC.swift
  8. 4 4
      AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateVC.swift
  9. 26 7
      AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateViewModel.swift
  10. 13 4
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSGenmojiModel.swift
  11. 12 1
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiGennerateCell.swift
  12. 1 1
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiItemCell.swift
  13. 5 4
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/ViewModel/TSGenmojiCollectionViewModel.swift
  14. 7 0
      AIEmoji/Business/TSSetingVC/SetingVC/TSSetingVC.swift
  15. 7 3
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextGeneralPictureVC/TSTextGeneralPictureVC.swift
  16. 98 20
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVC.swift
  17. 26 6
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVM.swift
  18. 4 4
      AIEmoji/Common/NetworkManager/TSNetWork/TSNetWork+Business.swift
  19. 5 5
      AIEmoji/Common/NetworkManager/TSNetWork/TSNetworkManager+Loading.swift
  20. 2 1
      AIEmoji/Common/NetworkManager/TSNetWork/TSNetworkManager.swift
  21. 6 4
      AIEmoji/Common/Purchase/TSPurchaseManager.swift

+ 16 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -42,6 +42,8 @@
 		A85E47922D6728A00018D62D /* TSTextGeneralPictureVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E47912D67289F0018D62D /* TSTextGeneralPictureVM.swift */; };
 		A85E47962D672ADA0018D62D /* TSTextPicGennerateVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E47952D672AD90018D62D /* TSTextPicGennerateVC.swift */; };
 		A85E47982D672AE70018D62D /* TSTextPicGennerateVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E47972D672AE40018D62D /* TSTextPicGennerateVM.swift */; };
+		A85E479B2D6808C40018D62D /* TSBigIconBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E479A2D6808C30018D62D /* TSBigIconBrowseVC.swift */; };
+		A85E479D2D6809DC0018D62D /* TSBigIconBrowseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E479C2D6809DA0018D62D /* TSBigIconBrowseCell.swift */; };
 		A89EA64B2D59A588000EB181 /* MessageKit in Frameworks */ = {isa = PBXBuildFile; productRef = A89EA64A2D59A588000EB181 /* MessageKit */; };
 		A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */; };
 		A89EA6552D59A9F4000EB181 /* TSChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6502D59A9F4000EB181 /* TSChatMessage.swift */; };
@@ -166,6 +168,8 @@
 		A85E47912D67289F0018D62D /* TSTextGeneralPictureVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextGeneralPictureVM.swift; sourceTree = "<group>"; };
 		A85E47952D672AD90018D62D /* TSTextPicGennerateVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextPicGennerateVC.swift; sourceTree = "<group>"; };
 		A85E47972D672AE40018D62D /* TSTextPicGennerateVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextPicGennerateVM.swift; sourceTree = "<group>"; };
+		A85E479A2D6808C30018D62D /* TSBigIconBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBigIconBrowseVC.swift; sourceTree = "<group>"; };
+		A85E479C2D6809DA0018D62D /* TSBigIconBrowseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBigIconBrowseCell.swift; sourceTree = "<group>"; };
 		A89EA64C2D59A9F4000EB181 /* CustomMessageFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomMessageFlowLayout.swift; sourceTree = "<group>"; };
 		A89EA64E2D59A9F4000EB181 /* TSLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSLayoutSizeCalculator.swift; sourceTree = "<group>"; };
 		A89EA64F2D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextLayoutSizeCalculator.swift; sourceTree = "<group>"; };
@@ -474,6 +478,15 @@
 			path = TSTextPicGennerateVC;
 			sourceTree = "<group>";
 		};
+		A85E47992D6808B30018D62D /* TSBigIconBrowseVC */ = {
+			isa = PBXGroup;
+			children = (
+				A85E479C2D6809DA0018D62D /* TSBigIconBrowseCell.swift */,
+				A85E479A2D6808C30018D62D /* TSBigIconBrowseVC.swift */,
+			);
+			path = TSBigIconBrowseVC;
+			sourceTree = "<group>";
+		};
 		A89EA64D2D59A9F4000EB181 /* Layout */ = {
 			isa = PBXGroup;
 			children = (
@@ -908,6 +921,7 @@
 		A8F776402D3B75EA00AA6E93 /* General */ = {
 			isa = PBXGroup;
 			children = (
+				A85E47992D6808B30018D62D /* TSBigIconBrowseVC */,
 				A89EA6BD2D5E03CD000EB181 /* Ex */,
 				A8F776412D3B75EF00AA6E93 /* TSBottomAlertVC.swift */,
 				A8F776432D3DE89900AA6E93 /* TSSmallIconBrowseVC */,
@@ -1201,6 +1215,7 @@
 				A8F7750A2D38EA8C00AA6E93 /* TSNetworkTool.swift in Sources */,
 				A8F7762D2D3A74A100AA6E93 /* TSGenmojiGennerateCell.swift in Sources */,
 				A89EA6BC2D5DFB12000EB181 /* TSViewController.swift in Sources */,
+				A85E479D2D6809DC0018D62D /* TSBigIconBrowseCell.swift in Sources */,
 				A89EA6832D59F4F9000EB181 /* TSChatViewController+ChatDelegate.swift in Sources */,
 				A89EA6A32D5B26E3000EB181 /* TSDBAIChatList.swift in Sources */,
 				A8F7753F2D39340E00AA6E93 /* TSSetingVC.swift in Sources */,
@@ -1212,6 +1227,7 @@
 				A89EA65F2D59AA11000EB181 /* TSChatViewController.swift in Sources */,
 				A89EA6C62D5F5C22000EB181 /* TSChatInputFullScreenVC.swift in Sources */,
 				A89EA6CA2D642C0A000EB181 /* TSChatViewController+SendMsg.swift in Sources */,
+				A85E479B2D6808C40018D62D /* TSBigIconBrowseVC.swift in Sources */,
 				A89EA6B12D5C9D0C000EB181 /* TSAIChatHistoryVC.swift in Sources */,
 				A8FB02B72D3E3A3D0031A396 /* TSEmojisChildViewModel.swift in Sources */,
 				A8F7754B2D39376800AA6E93 /* TSSettingListView.swift in Sources */,

+ 22 - 0
AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "refresh_gary@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "refresh_gary@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/refresh_gary@2x.png


BIN
AIEmoji/Assets.xcassets/Common/refresh_gary.imageset/refresh_gary@3x.png


+ 63 - 0
AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseCell.swift

@@ -0,0 +1,63 @@
+//
+//  TSBigIconBrowseCell.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/2/20.
+//
+
+
+class TSBigIconBrowseCell : TSBaseCollectionCell{
+
+    lazy var netWorkImageView : UIImageView = {
+        let netWorkImageView = UIImageView.createImageView(imageName: "",corner: 24.0)
+        return netWorkImageView
+    }()
+    
+    
+    lazy var textBtn: UIButton = {
+        let textBtn = UIButton.createButton(
+            backgroundColor: "#333333".uiColor,
+            font: .font(size: 12),
+            titleColor: .white,
+            corner: 16
+        )
+        textBtn.contentEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
+        return textBtn
+    }()
+    
+    lazy var vipImageView: UIImageView = {
+        let vipImageView = UIImageView.createImageView(imageName:"vip_side_icon")
+        vipImageView.contentMode = .scaleToFill
+        vipImageView.isHidden = true
+        return vipImageView
+    }()
+
+    override func creatUI() {
+        let w = k_ScreenWidth - 120
+        let h = w/kTextWHScale
+        bgContentView.addSubview(netWorkImageView)
+        netWorkImageView.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(0)
+            make.width.equalTo(w)
+            make.height.equalTo(h)
+        }
+        
+        bgContentView.addSubview(textBtn)
+        textBtn.snp.makeConstraints { make in
+            make.top.equalTo(netWorkImageView.snp.bottom).offset(20)
+            make.centerX.equalToSuperview()
+            make.leading.greaterThanOrEqualTo(16)
+            make.trailing.lessThanOrEqualTo(-16)
+            make.bottom.lessThanOrEqualTo(0)
+        }
+        
+        netWorkImageView.addSubview(vipImageView)
+        vipImageView.snp.makeConstraints { make in
+            make.width.height.equalTo(40)
+            make.top.equalTo(-5)
+            make.trailing.equalTo(5)
+        }
+        
+    }
+}

+ 207 - 0
AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift

@@ -0,0 +1,207 @@
+//
+//  TSBigIconBrowseVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/2/20.
+//
+
+private let cellId = "TSBigIconBrowseCell"
+class TSBigIconBrowseVC: TSBottomAlertVC {
+
+    
+    var dataModelArray = [TSGenmojiModel]()
+    var currentImage:UIImage?{
+        let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSBigIconBrowseCell
+        var image = cell?.netWorkImageView.image
+        image = image?.pngImage
+        return image
+    }
+
+    var currentModel:TSGenmojiModel?{
+        if let model = dataModelArray.safeObj(At: currentIndex){
+            return model
+        }
+        return nil
+    }
+    
+    
+    var currentIndex:Int = 0 {
+        didSet{
+            reloadUI()
+        }
+    }
+    
+    lazy var collectionView: UICollectionView = {
+
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        
+        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.backgroundColor = .clear
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        collectionView.register(TSBigIconBrowseCell.self, forCellWithReuseIdentifier: cellId)
+        collectionView.isPagingEnabled = true
+        collectionView.isHidden = true
+        if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
+            flowLayout.minimumInteritemSpacing = 0
+            flowLayout.minimumLineSpacing = 0
+            flowLayout.scrollDirection = .horizontal
+            flowLayout.itemSize = CGSize(width: k_ScreenWidth, height: 490*kDesignScale)
+        }
+        return collectionView
+    }()
+    
+    
+    lazy var leftBtn: UIButton = {
+        let leftBtn = UIButton.createButton(image: UIImage(named: "page_left")){ [weak self]  in
+            guard let self = self else { return }
+            self.collectionView.scrollToItem(at:  IndexPath(item: self.currentIndex-1, section: 0), at: .left, animated: true)
+        }
+        return leftBtn
+    }()
+    
+    lazy var rightBtn: UIButton = {
+        let rightBtn = UIButton.createButton(image: UIImage(named: "page_right")){ [weak self]  in
+            guard let self = self else { return }
+            self.collectionView.scrollToItem(at: IndexPath(item: self.currentIndex+1, section: 0), at: .left, animated: true)
+        }
+        return rightBtn
+    }()
+        
+    override func createView() {
+        super.createView()
+        submitBtn.isHidden = true
+        bottomView.frame = CGRectMake(0, 92, k_ScreenWidth, k_ScreenHeight-92)
+        cancelBtn.setTitle("Copy Text".localized, for: .normal)
+        
+        bottomView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.leading.trailing.equalTo(0)
+            make.top.equalTo(36)
+            make.bottom.equalTo(confirmBtn.snp.top).offset(-30)
+        }
+        
+        bottomView.addSubview(leftBtn)
+        leftBtn.snp.makeConstraints { make in
+            make.leading.equalTo(17)
+            make.top.equalTo(244)
+            make.width.height.equalTo(40)
+        }
+        
+        bottomView.addSubview(rightBtn)
+        rightBtn.snp.makeConstraints { make in
+            make.trailing.equalTo(-18)
+            make.top.equalTo(244)
+            make.width.height.equalTo(40)
+        }
+        
+        kDelayMainShort {
+            self.collectionView.isHidden = false
+            self.collectionView.reloadData()
+            self.collectionView.setContentOffset(CGPoint(x: CGFloat(self.currentIndex) * self.collectionView.frame.size.width, y: 0), animated: false)
+
+            if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
+                flowLayout.itemSize = self.collectionView.bounds.size
+            }
+        }
+    }
+    
+    
+    @objc override func clickCancelBtn(){
+        
+        if JudgeVip(){
+            return
+        }
+  
+        if let image = currentImage{
+            //拷贝文字到截切板
+            UIPasteboard.general.string = currentModel?.request.prompt
+            kSavePhotoSuccesswShared.show(atView: self.view,text: "Copy Successfully".localized,showViewBtn:false)
+        }else{
+            kShowToastDataMissing()
+        }
+    }
+    
+    @objc override func clickConfirmBtn(){
+        
+        if JudgeVip(){
+            return
+        }
+        
+        if let image = currentImage{
+            PhotoManagerShared.saveImageToAlbum(image) { success, error in
+                if success {
+                    kSavePhotoSuccesswShared.show(atView: self.view)
+                }else{
+                    debugPrint(error)
+                }
+            }
+        }else{
+            kShowToastDataMissing()
+        }
+    }
+    
+    
+    func JudgeVip() -> Bool {
+        return kJudgeVip(externalBool: currentModel?.response.vip ?? false , vc: self, closePageBlock: nil)
+    }
+}
+
+
+extension TSBigIconBrowseVC {
+    
+    func reloadUI() {
+        //判断前后是否还有,以此来确定左右翻页按钮
+        var isHiddenLeft = false
+        var isHiddenRight = false
+        if dataModelArray.count == 1{
+            isHiddenLeft = true
+            isHiddenRight = true
+        }else if currentIndex == 0 {
+            isHiddenLeft = true
+        }else if currentIndex+1 >= dataModelArray.count {
+            isHiddenRight = true
+        }
+        
+        leftBtn.isHidden = isHiddenLeft
+        rightBtn.isHidden = isHiddenRight
+    }
+}
+
+//MARK: UICollectionViewDataSource
+extension TSBigIconBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate {
+    
+    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
+        resetIndexWithOffset(scrollView)
+    }
+
+    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
+        resetIndexWithOffset(scrollView)
+    }
+
+    private func resetIndexWithOffset(_ scrollView: UIScrollView) {
+        let item = Int((scrollView.contentOffset.x / scrollView.bounds.width).rounded())
+        currentIndex = item
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return dataModelArray.count
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TSBigIconBrowseCell
+        if let model = dataModelArray.safeObj(At: indexPath.item){
+            cell.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder: kPlaceholderImage,contentMode: .scaleAspectFill)
+            cell.vipImageView.isHidden = !model.response.vip
+            cell.textBtn.setTitle(model.request.prompt, for: .normal)
+        }
+        return cell
+    }
+    
+}

+ 0 - 2
AIEmoji/Business/General/TSBottomAlertVC.swift

@@ -7,8 +7,6 @@
 
 class TSBottomAlertVC: TSBaseVC {
     
-    
-    
     lazy var topBgView: UIView = {
         let topBgView = UIView(frame: CGRectMake(0, 0, k_ScreenWidth, k_ScreenHeight-400))
         topBgView.backgroundColor = .black.withAlphaComponent(0.5)

+ 4 - 4
AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateVC.swift

@@ -52,6 +52,7 @@ class TSGenmojiGennerateVC: TSBottomAlertVC {
     }
     
     override func closePage() {
+        viewModel.cancelAllRequest()
         if let model = imageModel {
             complete(model)
         }
@@ -83,7 +84,6 @@ class TSGenmojiGennerateVC: TSBottomAlertVC {
         }
     }
     
-    
     override func dealThings() {
         viewModel.creatImageEmoji(text: self.aiText)
         viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
@@ -126,7 +126,7 @@ extension TSGenmojiGennerateVC {
         submitBtn.isHidden = true
         cancelBtn.isHidden = true
         confirmBtn.isHidden = true
-        xBtn.isHidden = true
+//        xBtn.isHidden = true
         isClickTheBlankClosePage = false
     }
     
@@ -148,7 +148,7 @@ extension TSGenmojiGennerateVC {
         submitBtn.isHidden = false
         cancelBtn.isHidden = true
         confirmBtn.isHidden = true
-        xBtn.isHidden = false
+//        xBtn.isHidden = false
         isClickTheBlankClosePage = true
     }
     
@@ -158,7 +158,7 @@ extension TSGenmojiGennerateVC {
         submitBtn.isHidden = true
         cancelBtn.isHidden = false
         confirmBtn.isHidden = false
-        xBtn.isHidden = false
+//        xBtn.isHidden = false
         imageModel = model
         isClickTheBlankClosePage = true
         

+ 26 - 7
AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateViewModel.swift

@@ -6,7 +6,7 @@
 //
 
 import Combine
-
+import Alamofire
 enum TSProgressState  {
     case none
     case start
@@ -18,18 +18,27 @@ enum TSProgressState  {
 }
 
 class TSGenmojiGennerateViewModel {
-   
+
+    var creatRequest:DataRequest?
+    var queryRequest:DataRequest?
+    var stopNetwork = false
+    
     @Published var stateDatauPblished:(TSProgressState,TSGenmojiModel?) = (TSProgressState.none,nil)
     var aiText:String = ""
     
     func creatImageEmoji(text:String) {
+        stopNetwork = false
         aiText = text
         stateDatauPblished = (.start,nil)
-        TSNetworkShared.post(urlType: .imageEmoji,parameters: ["prompt":text]) { data,error in
+        creatRequest = TSNetworkShared.post(urlType: .imageEmoji,parameters: ["prompt":text]) { [weak self] data,error in
+            guard let self = self else { return }
+            
             if let dataDict = data as? [String:Any] ,
                dataDict.safeInt(forKey: "code") == 200,
                let actionId = dataDict["actionId"] as? Int{
-                self.getActionInfo(action_id:actionId)
+                if stopNetwork == false {
+                    self.getActionInfo(action_id:actionId)
+                }
             }else{
                 self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
             }
@@ -37,7 +46,8 @@ class TSGenmojiGennerateViewModel {
     }
     
     func getActionInfo(action_id:Int){
-        TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { data,error in
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
             if let result = kNetWorkResultSuccess(data: data) {
                 if let genmojiModel = TSGenmojiModel(JSON: result) {
                     switch genmojiModel.actionStatus {
@@ -47,8 +57,10 @@ class TSGenmojiGennerateViewModel {
                     case .failed:
                         self.stateDatauPblished = (.failed(kNetWorkMessage(data: data) ?? ""),nil)
                     default:
-                        kDelayOnMainThread(1.0) {
-                            self.getActionInfo(action_id: action_id)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(1.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
                         }
                     }
                 }
@@ -58,6 +70,13 @@ class TSGenmojiGennerateViewModel {
         }
     }
     
+    
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
+    
 }
 
 

+ 13 - 4
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSGenmojiModel.swift

@@ -22,7 +22,7 @@ class TSGenmojiModel: TSBaseModel {
     var id:Int = 0
     var actionType:String = ""
     var comments:String = ""
-    var request:String = ""
+    var request:TSGenmojiRequestModel = TSGenmojiRequestModel()
     var response:TSGenmojiResponseModel = TSGenmojiResponseModel()
     var createdTimestamp:Int = 0
     var status:String = ""
@@ -35,7 +35,7 @@ class TSGenmojiModel: TSBaseModel {
         id           <- map["id"]
         actionType   <- map["actionType"]
         comments     <- map["comments"]
-        request      <- map["request"]
+        request      <- (map["request"],JsonStringTransform<TSGenmojiRequestModel>())
         response           <- (map["response"],JsonStringTransform<TSGenmojiResponseModel>())
         createdTimestamp   <- map["createdTimestamp"]
         status     <- map["status"]
@@ -46,6 +46,17 @@ class TSGenmojiModel: TSBaseModel {
     }
 }
 
+class TSGenmojiRequestModel : TSBaseModel {
+    var prompt:String = ""
+    var width:Int = 0
+    var height:Int = 0
+    override func mapping(map: ObjectMapper.Map) {
+        prompt              <- map["prompt"]
+        width               <- map["width"]
+        height              <- map["height"]
+    }
+}
+
 class TSGenmojiResponseModel : TSBaseModel {
     var resultUrl:String = ""
     var vip:Bool = false
@@ -57,5 +68,3 @@ class TSGenmojiResponseModel : TSBaseModel {
 
 
 
-
-

+ 12 - 1
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiGennerateCell.swift

@@ -74,7 +74,18 @@ class TSGenmojiGennerateCell : TSBaseCollectionCell{
     
     override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
         super.renderView(with: object, component: component, attributes: attributes)
-        submitBtn.setTitle(getVipText(), for: .normal)
+        
+        var title = "Generate"
+        if kPurchaseDefault.isVip == false,
+           let itemModel = object as? TSGenmojiCoLItemModel{
+            if itemModel.style == .generate{
+                title = "Generate (\(kPurchaseDefault.freeNum(type: .generatePic)))"
+            }else if itemModel.style == .textPicGenerate{
+                title = "Generate (\(kPurchaseDefault.freeNum(type: .textGeneratePic)))"
+            }
+        }
+        submitBtn.setTitle(title, for: .normal)
+
     }
 }
 

+ 1 - 1
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiItemCell.swift

@@ -29,7 +29,7 @@ class TSGenmojiItemCell: TSBaseCollectionCell {
         super.renderView(with: object, component: component, attributes: attributes)
         
         if let itemModel = object as? TSGenmojiCoLItemModel{
-            showImageView.setAsyncImage(urlString: itemModel.dataModel.response.resultUrl)
+            showImageView.setAsyncImage(urlString: itemModel.dataModel.response.resultUrl,contentMode: .scaleAspectFill)
         }
     }
     

+ 5 - 4
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/ViewModel/TSGenmojiCollectionViewModel.swift

@@ -8,9 +8,8 @@
 
 import ObjectMapper
 
-private let kTextPicHistoryScale = 165.0/293.0  //UI 设置尺寸
-private let kTextPicHistoryW = k_ScreenWidth-32.0-12.0
-private let kTextPicHistoryH = kTextPicHistoryW/kTextPicHistoryScale
+private let kTextPicHistoryW = (k_ScreenWidth-32.0-14.0)/2.0
+private let kTextPicHistoryH = kTextPicHistoryW/kTextWHScale
 
 class TSGenmojiColViewModel: TSBaseModel {
     
@@ -33,8 +32,10 @@ enum TSGenmojiCoLStyple : Int {
         switch self {
         case .generate,.textPicGenerate:
             return UIEdgeInsets(top: 17, left: 17, bottom: 20, right: 15)
-        case .history,.textPicHistory:
+        case .history:
             return UIEdgeInsets(top: 0, left: 24, bottom: 10, right: 24)
+        case .textPicHistory:
+            return UIEdgeInsets(top: 0, left: 16, bottom: 10, right: 16)
         }
     }
         

+ 7 - 0
AIEmoji/Business/TSSetingVC/SetingVC/TSSetingVC.swift

@@ -68,6 +68,13 @@ class TSSetingVC: TSBaseVC {
             }
             
         }.store(in: &cancellable)
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
     }
     
+    @objc func vipInfoChanged() {
+        kExecuteOnMainThread {
+            self.viewModel.isViper = PurchaseManager.default.isVip
+        }
+    }
 }

+ 7 - 3
AIEmoji/Business/TSTextGeneralPictureVC/TSTextGeneralPictureVC/TSTextGeneralPictureVC.swift

@@ -90,7 +90,7 @@ class TSTextGeneralPictureVC: TSBaseVC {
                     dataModelArray.append(itemModel.dataModel)
                 }
                 
-                let browseVC = TSSmallIconBrowseVC()
+                let browseVC = TSBigIconBrowseVC()
                 browseVC.dataModelArray = dataModelArray
                 browseVC.currentIndex = indexPath.item
                 kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
@@ -114,7 +114,7 @@ class TSTextGeneralPictureVC: TSBaseVC {
             make.edges.equalToSuperview()
         }
         
-        
+        collectionComponent.collectionView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickCollectionView)))
         collectionComponent.clear()
         collectionComponent.reloadView(with:viewModel.colDataArray)
         
@@ -131,13 +131,17 @@ class TSTextGeneralPictureVC: TSBaseVC {
             self.collectionComponent.reloadData()
         }
     }
+    
+    @objc func clickCollectionView() {
+        view.endEditing(true)
+    }
 }
 
 extension TSTextGeneralPictureVC {
     func generateImage(text:String) {
         
         //判断 vip
-        if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .generatePic) == false, vc: self) {[weak self] in
+        if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .textGeneratePic) == false, vc: self) {[weak self] in
             guard let self = self else { return }
         }{ return }
         

+ 98 - 20
AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVC.swift

@@ -10,6 +10,7 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
     var imageModel:TSGenmojiModel?
     var complete:((TSGenmojiModel)->Void)
     var aiText:String
+
     init(aiText: String,complete:@escaping ((TSGenmojiModel)->Void)) {
         self.aiText = aiText
         self.complete = complete
@@ -22,7 +23,8 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
     }
     
     lazy var netWorkImageView : UIImageView = {
-        let netWorkImageView = UIImageView.createImageView(imageName: "",corner: 24.0)
+        let netWorkImageView = UIImageView.createImageView(imageName: "",corner: 16.0)
+        netWorkImageView.isHidden = true
         return netWorkImageView
     }()
     
@@ -32,10 +34,48 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
         return generateInView
     }()
     
+    //大保存按钮
+    lazy var bigSaveBtn: UIButton = {
+        let bigSaveBtn = kCreateNormalSubmitBtn(title: "Save".localized) { [weak self]  in
+            guard let self = self else { return }
+            clickConfirmBtn()
+        }
+        bigSaveBtn.isHidden = true
+        return bigSaveBtn
+    }()
+    
+    lazy var regenerateBtn: UIButton = {
+        let regenerateBtn = UIButton.createButton(
+            title: "regenerate",
+            image: UIImage(named: "refresh_gary"),
+            backgroundColor:.white.withAlphaComponent(0.1),
+            font: .font(size: 12),
+            titleColor: .white.withAlphaComponent(0.6),
+            corner: 8.0)
+        { [weak self]  in
+            guard let self = self else { return }
+            clickSubmitBtn()
+        }
+        regenerateBtn.contentEdgeInsets = UIEdgeInsets(top: 4, left: 7, bottom: 4, right: 7)
+        regenerateBtn.imageEdgeInsets = UIEdgeInsets(top: 0, left: -4, bottom: 0, right: 0)
+        regenerateBtn.isHidden = true
+        return regenerateBtn
+    }()
+    
     override func createView() {
         super.createView()
         
         bottomView.frame = CGRectMake(0, 92, k_ScreenWidth, k_ScreenHeight-92)
+        cancelBtn.isHidden = true
+        confirmBtn.isHidden = true
+        
+        bottomView.addSubview(bigSaveBtn)
+        bigSaveBtn.snp.makeConstraints { make in
+            make.bottom.equalTo(-34)
+            make.centerX.equalToSuperview()
+            make.width.equalTo(329)
+            make.height.equalTo(60)
+        }
         
         bottomView.addSubview(generateInView)
         generateInView.snp.makeConstraints { make in
@@ -43,16 +83,33 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
         }
         
         bottomView.addSubview(netWorkImageView)
+//        netWorkImageView.snp.makeConstraints { make in
+//            make.top.equalTo(94)
+//            make.centerX.equalToSuperview()
+//            make.width.equalTo(249*kDesignScale)
+//            make.height.equalTo(441*kDesignScale)
+//        }
+        
+        let netWorkImageViewW = k_ScreenWidth - 120.0
+        let netWorkImageViewH = netWorkImageViewW/kTextWHScale
         netWorkImageView.snp.makeConstraints { make in
-            make.top.equalTo(94)
+            make.top.equalTo(90)
             make.centerX.equalToSuperview()
-            make.width.equalTo(249*kDesignScale)
-            make.height.equalTo(441*kDesignScale)
+            make.width.equalTo(netWorkImageViewW)
+            make.height.equalTo(netWorkImageViewH)
+        }
+
+        bottomView.addSubview(regenerateBtn)
+        regenerateBtn.snp.makeConstraints { make in
+            make.top.equalTo(netWorkImageView.snp.bottom).offset(16)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(28)
         }
         
     }
     
     override func closePage() {
+        viewModel.cancelAllRequest()
         if let model = imageModel {
             complete(model)
         }
@@ -61,17 +118,20 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
     
     
     
+    
+    //重试
     @objc override func clickSubmitBtn(){
         viewModel.creatImageEmoji(text:aiText)
     }
     
-    @objc override func clickCancelBtn(){
-        if let image = getSuccessImage() {
-            UIDevice.copyImage(image: image)
-            kSavePhotoSuccesswShared.show(atView: self.view,text: "Copy Successfully".localized,showViewBtn:false)
-        }
-    }
+//    @objc override func clickCancelBtn(){
+//        if let image = getSuccessImage() {
+//            UIDevice.copyImage(image: image)
+//            kSavePhotoSuccesswShared.show(atView: self.view,text: "Copy Successfully".localized,showViewBtn:false)
+//        }
+//    }
     
+    //保存功能
     @objc override func clickConfirmBtn(){
         if let image = getSuccessImage() {
             PhotoManagerShared.saveImageToAlbum(image) { success, error in
@@ -84,7 +144,6 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
         }
     }
     
-    
     override func dealThings() {
         viewModel.creatImageEmoji(text: self.aiText)
         viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
@@ -92,6 +151,7 @@ class TSTextPicGennerateVC: TSBottomAlertVC {
             self.upDateView(state: state, model: model)
         }.store(in: &cancellable)
     }
+    
 }
 extension TSTextPicGennerateVC {
     
@@ -125,10 +185,13 @@ extension TSTextPicGennerateVC {
         generateInView.showLoading(text: "Generating...".localized)
         generateInView.isRotating = true
         submitBtn.isHidden = true
-        cancelBtn.isHidden = true
+//        cancelBtn.isHidden = true
+//        xBtn.isHidden = false
         confirmBtn.isHidden = true
-        xBtn.isHidden = false
+        bigSaveBtn.isHidden = true
         isClickTheBlankClosePage = false
+        regenerateBtn.isHidden = true
+        netWorkImageView.isHidden = true
     }
     
     func showError(text:String?){
@@ -137,30 +200,45 @@ extension TSTextPicGennerateVC {
         generateInView.showError(text: msg)
         generateInView.isRotating = false
         submitBtn.isHidden = false
-        cancelBtn.isHidden = true
-        confirmBtn.isHidden = true
-        xBtn.isHidden = false
+        bigSaveBtn.isHidden = true
+//        cancelBtn.isHidden = true
+//        confirmBtn.isHidden = true
+//        xBtn.isHidden = false
         isClickTheBlankClosePage = true
+        regenerateBtn.isHidden = true
+        netWorkImageView.isHidden = true
     }
     
     func showSuccess(model:TSGenmojiModel){
         generateInView.isHidden = true
         generateInView.isRotating = false
         submitBtn.isHidden = true
-        cancelBtn.isHidden = false
-        confirmBtn.isHidden = false
-        xBtn.isHidden = false
+        bigSaveBtn.isHidden = false
+//        cancelBtn.isHidden = true
+//        confirmBtn.isHidden = false
+//        xBtn.isHidden = false
         imageModel = model
         isClickTheBlankClosePage = true
+        regenerateBtn.isHidden = false
         
         cancelBtn.isEnabled = false
         confirmBtn.isEnabled = false
+        netWorkImageView.isHidden = false
+        
+//        netWorkImageView.snp.updateConstraints { make in
+//            make.top.equalTo(94)
+//            make.centerX.equalToSuperview()
+//            make.width.equalTo(249*kDesignScale)
+//            make.height.equalTo(441*kDesignScale)
+//        }
+        
+        
         self.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder:kPlaceholderImage){ [weak self] image in
             guard let self = self else { return }
             cancelBtn.isEnabled = true
             confirmBtn.isEnabled = true
         }
         
-        kPurchaseDefault.useOnceForFree(type: .generatePic)
+        kPurchaseDefault.useOnceForFree(type: .textGeneratePic)
     }
 }

+ 26 - 6
AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVM.swift

@@ -6,14 +6,23 @@
 //
 
 import Combine
+import Alamofire
+
+let kTextPicW = 800.0
+let kTextPicH = 1440.0
+let kTextWHScale = kTextPicW/kTextPicH
 
 class TSTextPicGennerateVM {
+    
+    var creatRequest:DataRequest?
+    var queryRequest:DataRequest?
+    var stopNetwork = false
    
     @Published var stateDatauPblished:(TSProgressState,TSGenmojiModel?) = (TSProgressState.none,nil)
     var aiText:String = ""
     
     //width 和 height 必须是 32 的倍数
-    func creatImageEmoji(text:String,width:Int = 384 ,height:Int = 832) {
+    func creatImageEmoji(text:String,width:Int = Int(kTextPicW) ,height:Int = Int(kTextPicH)) {
         aiText = text
         let postDict:[String : Any] = [
             "prompt":text,
@@ -21,11 +30,14 @@ class TSTextPicGennerateVM {
             "height":height
         ]
         stateDatauPblished = (.start,nil)
-        TSNetworkShared.post(urlType: .textPicCreate,parameters: postDict) { data,error in
+        creatRequest = TSNetworkShared.post(urlType: .textPicCreate,parameters: postDict) { [weak self] data,error in
+            guard let self = self else { return }
             if let dataDict = data as? [String:Any] ,
                dataDict.safeInt(forKey: "code") == 200,
                let actionId = dataDict["actionId"] as? Int{
-                self.getActionInfo(action_id:actionId)
+                if stopNetwork == false {
+                    self.getActionInfo(action_id:actionId)
+                }
             }else{
                 self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
             }
@@ -33,7 +45,8 @@ class TSTextPicGennerateVM {
     }
     
     func getActionInfo(action_id:Int){
-        TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { data,error in
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
             if let result = kNetWorkResultSuccess(data: data) {
                 if let genmojiModel = TSGenmojiModel(JSON: result) {
                     switch genmojiModel.actionStatus {
@@ -43,8 +56,10 @@ class TSTextPicGennerateVM {
                     case .failed:
                         self.stateDatauPblished = (.failed(kNetWorkMessage(data: data) ?? ""),nil)
                     default:
-                        kDelayOnMainThread(1.0) {
-                            self.getActionInfo(action_id: action_id)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(1.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
                         }
                     }
                 }
@@ -54,4 +69,9 @@ class TSTextPicGennerateVM {
         }
     }
     
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
 }

+ 4 - 4
AIEmoji/Common/NetworkManager/TSNetWork/TSNetWork+Business.swift

@@ -31,9 +31,9 @@ extension TSNetworkManager {
         parameters: [String: Any]? = nil,
         responseType: T.Type? = nil,
         completion: @escaping (Result<Any, Error>) -> Void
-    ) {
+    ) -> DataRequest  {
         let urlString = urlType.getUrlString()
-        request(method: .get, urlString: urlString, parameters:parameters) { result in
+        return request(method: .get, urlString: urlString, parameters:parameters) { result in
             completion(result)
         }
     }
@@ -50,9 +50,9 @@ extension TSNetworkManager {
         parameters: [String: Any]? = nil,
         responseType: T.Type? = nil,
         completion: @escaping (Result<Any, Error>) -> Void
-    ) {
+    ) -> DataRequest {
         let urlString = urlType.getUrlString()
-        request(method: .post, urlString: urlString, parameters:parameters) { result in
+        return request(method: .post, urlString: urlString, parameters:parameters) { result in
             completion(result)
         }
     }

+ 5 - 5
AIEmoji/Common/NetworkManager/TSNetWork/TSNetworkManager+Loading.swift

@@ -4,7 +4,7 @@
 //
 //  Created by 100Years on 2025/1/16.
 //
-
+import Alamofire
 extension TSNetworkManager {
     
     /// 通用 get 请求
@@ -14,7 +14,7 @@ extension TSNetworkManager {
         responseType: T.Type? = nil,
         animationView:UIView? = nil,
         completion: @escaping (Any?, Error?) -> Void
-    ) {
+    ) -> DataRequest {
         
         var isShowAnimation = false
         if animationView != nil {
@@ -25,7 +25,7 @@ extension TSNetworkManager {
             TSToastShared.showLoading(containerView: view)
         }
 
-        get(urlType: urlType, parameters:parameters,responseType:responseType) { result in
+        return get(urlType: urlType, parameters:parameters,responseType:responseType) { result in
             
             if isShowAnimation {
                 TSToastShared.hideLoading()
@@ -55,7 +55,7 @@ extension TSNetworkManager {
         responseType: T.Type? = nil,
         animationView:UIView? = nil,
         completion: @escaping (Any?, Error?) -> Void
-    ) {
+    ) -> DataRequest {
         var isShowAnimation = false
         if animationView != nil {
             isShowAnimation = true
@@ -65,7 +65,7 @@ extension TSNetworkManager {
             TSToastShared.showLoading(containerView: view)
         }
 
-        post(urlType: urlType, parameters:parameters,responseType:responseType){ result in
+        return post(urlType: urlType, parameters:parameters,responseType:responseType){ result in
             
             if isShowAnimation {
                 TSToastShared.hideLoading()

+ 2 - 1
AIEmoji/Common/NetworkManager/TSNetWork/TSNetworkManager.swift

@@ -84,7 +84,7 @@ class TSNetworkManager {
         urlString: String,
         parameters: [String: any Any & Sendable]? = nil,
         completion: @escaping (Result<Any, Error>) -> Void
-    ) {
+    ) -> DataRequest{
         dePrint("✈️✈️✈️网络请求:\(urlString)")
         dePrint("✈️✈️✈️参数:\(String(describing: parameters))")
         
@@ -96,6 +96,7 @@ class TSNetworkManager {
         request.responseString { response in
                 self.handleResponse(response, completion: completion)
             }
+        return request
     }
     
     private func handleResponse(

+ 6 - 4
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -16,8 +16,9 @@ public enum PremiumPeriod: String, CaseIterable {
 }
 
 public enum VipFreeNumType: String, CaseIterable {
-    case generatePic    = "kGeneratePicFreeNum"
-    case aichat         = "kAIChatFreeNum"
+    case generatePic            = "kGeneratePicFreeNum"
+    case aichat                 = "kAIChatFreeNum"
+    case textGeneratePic        = "kTextGeneratePicFreeNum"
 }
 
 public struct PurchaseProduct {
@@ -139,7 +140,7 @@ public class PurchaseManager: NSObject {
 
     @objc public var isVip: Bool {
         #if DEBUG
-        return true
+//        return true
         #endif
         guard let expiresDate = expiredDate else {
             return false
@@ -575,7 +576,8 @@ extension PurchaseManager {
         }else{
             freeDict = [
                 VipFreeNumType.generatePic.rawValue:3,
-                VipFreeNumType.aichat.rawValue:3
+                VipFreeNumType.aichat.rawValue:3,
+                VipFreeNumType.textGeneratePic.rawValue:3
             ]
             saveForFree()
         }