Browse Source

功能点开发完毕,接下来组装逻辑

100Years 1 week ago
parent
commit
7ef346e715

+ 12 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -260,6 +260,7 @@
 		A8D638472DB21FAD00A96C0E /* TSBusinessFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */; };
 		A8D638482DB21FAD00A96C0E /* TSDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */; };
 		A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638492DB252F000A96C0E /* TSAIListHistoryBaseCell.swift */; };
+		A8DFCDAF2E445C4E005A6D44 /* TSAIPhotoBrowsePageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8DFCDAE2E445C4D005A6D44 /* TSAIPhotoBrowsePageVC.swift */; };
 		A8EB1A642E30EA24001F58D7 /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB1A632E30EA22001F58D7 /* KeychainManager.swift */; };
 		A8EB1A662E30FA78001F58D7 /* TSAppOtherAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB1A652E30FA71001F58D7 /* TSAppOtherAlertVC.swift */; };
 		A8EB1AA02E320438001F58D7 /* Pixel World.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = A8EB1A982E320438001F58D7 /* Pixel World.mp4 */; };
@@ -662,6 +663,7 @@
 		A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBusinessFileManager.swift; sourceTree = "<group>"; };
 		A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSDownloadManager.swift; sourceTree = "<group>"; };
 		A8D638492DB252F000A96C0E /* TSAIListHistoryBaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListHistoryBaseCell.swift; sourceTree = "<group>"; };
+		A8DFCDAE2E445C4D005A6D44 /* TSAIPhotoBrowsePageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoBrowsePageVC.swift; sourceTree = "<group>"; };
 		A8EB1A632E30EA22001F58D7 /* KeychainManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = "<group>"; };
 		A8EB1A652E30FA71001F58D7 /* TSAppOtherAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAppOtherAlertVC.swift; sourceTree = "<group>"; };
 		A8EB1A852E320438001F58D7 /* Animal Diving Show.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Animal Diving Show.mp4"; sourceTree = "<group>"; };
@@ -1336,6 +1338,7 @@
 		A80EDDDC2D6EB17D003CD332 /* TSPTPGeneratorVC */ = {
 			isa = PBXGroup;
 			children = (
+				A8DFCDAD2E445C49005A6D44 /* TSAIPhotoBrowsePageVC */,
 				A804B9902DC1CCE600C494C7 /* TSAbnormalPopUpAlertVC */,
 				A88508B42DBF1408000FBCEC /* TSGennertatorSelectStyleVC */,
 				A885088B2DBCE7B8000FBCEC /* TSPTPHistoryVC */,
@@ -2107,6 +2110,14 @@
 			path = TSAIListVideoPlayerVC;
 			sourceTree = "<group>";
 		};
+		A8DFCDAD2E445C49005A6D44 /* TSAIPhotoBrowsePageVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8DFCDAE2E445C4D005A6D44 /* TSAIPhotoBrowsePageVC.swift */,
+			);
+			path = TSAIPhotoBrowsePageVC;
+			sourceTree = "<group>";
+		};
 		A8EB383F2E13BB07002F90E9 /* View */ = {
 			isa = PBXGroup;
 			children = (
@@ -2964,6 +2975,7 @@
 				A80EDD602D6C3F82003CD332 /* MarkdownElement.swift in Sources */,
 				A80EDD612D6C3F82003CD332 /* MarkdownLink+AppKit.swift in Sources */,
 				A80EDD622D6C3F82003CD332 /* MarkdownLink.swift in Sources */,
+				A8DFCDAF2E445C4E005A6D44 /* TSAIPhotoBrowsePageVC.swift in Sources */,
 				A8BA76722DA65A95000B6707 /* TSAIUploadPhotoBaseVC.swift in Sources */,
 				60EE9A782E386EB200565900 /* TSAIModelElementView.swift in Sources */,
 				A80EDD632D6C3F82003CD332 /* MarkdownAutomaticLink.swift in Sources */,

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

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

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


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


+ 341 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSAIPhotoBrowsePageVC/TSAIPhotoBrowsePageVC.swift

@@ -0,0 +1,341 @@
+//
+//  TSAIPhotoBrowsePageVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/8/6.
+//
+import RealmSwift
+private let bottomViewH = 60+k_Height_safeAreaInsetsBottom()
+class TSAIPhotoBrowsePageVC: TSBaseVC {
+
+    var browserPageVC:TSAIPhotoBrowsePageViewVC
+    public init(dataItems: [Any], startIndex: Int = 0) {
+        browserPageVC = TSAIPhotoBrowsePageViewVC(dataItems: dataItems, startIndex: startIndex)
+        super.init()
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    var deleteComplete:((TSActionInfoModel)->Void)?
+
+    var currentIndex:Int{
+        return browserPageVC.currentIndex
+    }
+    
+    var currentModel:TSActionInfoModel?{
+        if let model = browserPageVC.dataItems.safeObj(At: currentIndex) as? TSActionInfoModel{
+            return model
+        }
+        return nil
+    }
+    
+
+
+    lazy var bottomView: UIView = {
+        let bottom = 60+k_Height_safeAreaInsetsBottom()
+        let bottomView = UIView(frame: CGRectMake(0, k_ScreenHeight-bottomViewH, k_ScreenWidth, bottomViewH))
+        let colorView = UIView.creatColor(color: "#222222".uiColor)
+        colorView.frame = bottomView.bounds
+        colorView.cornersRound(radius: 20, corner: [.topLeft,.topRight])
+        bottomView.addSubview(colorView)
+
+        return bottomView
+    }()
+    
+    //左边分享按钮
+    lazy var shareBtn: TSVerticalButton = {
+        let shareBtn = TSVerticalButton()
+        shareBtn.setUpButton(title: "Share".localized,
+                                  image: UIImage(named: "share"),
+                                  font: .font(size: 11),
+                                  titleColor: .white.withAlphaComponent(0.8)){ [weak self]  in
+            guard let self = self else { return }
+            clickShare()
+        }
+        shareBtn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
+        return shareBtn
+    }()
+    
+    //保存按钮
+    lazy var bigSaveBtn: UIButton = {
+        let bigSaveBtn = kCreateNormalSubmitBtn(title: "Save".localized) { [weak self]  in
+            guard let self = self else { return }
+            clickSubmitBtn()
+        }
+        bigSaveBtn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        bigSaveBtn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+        bigSaveBtn.frame = CGRectMake(0, 0, 252, 44)
+        bigSaveBtn.cornerRadius = 22.0
+        kSetBtnVipIcon(btn: bigSaveBtn, show: true)
+        return bigSaveBtn
+    }()
+    
+    lazy var xBtn: UIButton = {
+        let xBtn = UIButton.createButton(image: UIImage(named: "close_gray")) { [weak self]  in
+            guard let self = self else { return }
+            clickXBtn()
+        }
+        return xBtn
+    }()
+    
+    
+    lazy var deleteBtn: UIButton = {
+        let deleteBtn = UIButton.createButton(image: UIImage(named: "delete_bg_gray")) { [weak self]  in
+            guard let self = self else { return }
+            showCustomAlert(message: "Are you sure to delete".localized, deleteHandler:  { [weak self]  in
+                guard let self = self else { return }
+                if let currentModel = currentModel {
+                    deleteComplete?(currentModel)
+                    browserPageVC.removePage(at: currentIndex, animated: true)
+                    if browserPageVC.dataItems.count <= 0 {
+                        self.clickXBtn()
+                    }
+                }
+            })
+        }
+        return deleteBtn
+    }()
+    
+    
+    override func createView() {
+        super.createView()
+        
+        setNavBarViewHidden(true)
+        
+
+        contentView.addSubview(browserPageVC.view)
+        browserPageVC.view.snp.makeConstraints { make in
+            make.leading.trailing.top.equalTo(0)
+            make.bottom.equalTo(-bottomViewH)
+        }
+        self.addChild(browserPageVC)
+        
+        //关闭按钮
+        contentView.addSubview(xBtn)
+        xBtn.snp.makeConstraints { make in
+            make.top.equalTo(k_Height_StatusBar + 4)
+            make.leading.equalTo(16)
+            make.width.equalTo(36)
+            make.height.equalTo(36)
+        }
+        
+        contentView.addSubview(deleteBtn)
+        deleteBtn.snp.makeConstraints { make in
+            make.top.equalTo(k_Height_StatusBar + 4)
+            make.trailing.equalTo(-16)
+            make.width.equalTo(36)
+            make.height.equalTo(36)
+        }
+        
+        let bottomBtnTop:CGFloat = 8.0
+        contentView.addSubview(bottomView)
+        bottomView.addSubview(bigSaveBtn)
+        bigSaveBtn.snp.makeConstraints { make in
+            make.top.equalTo(bottomBtnTop)
+            make.trailing.equalTo(-16)
+            make.width.equalTo(252*kDesignScale)
+            make.height.equalTo(44)
+        }
+        
+        bottomView.addSubview(shareBtn)
+        shareBtn.snp.makeConstraints { make in
+            make.top.equalTo(bottomBtnTop)
+            make.leading.equalTo(16)
+            make.width.equalTo(shareBtn.intrinsicContentSize.width)
+            make.height.equalTo(44)
+        }
+        
+    }
+    
+    override func dealThings() {
+        addPullDownClosePage()
+    }
+    @objc func clickSubmitBtn(){
+  
+        guard let currentModel = currentModel else { return }
+        if currentModel.modelType != .example{
+            if kJudgeVip(externalBool: true,vc: self) {
+                return
+            }
+        }
+
+        let urlString = currentModel.response.resultUrl
+        if currentModel.isVideo {
+            TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
+                if let url = url {
+                    PhotoManagerShared.saveVideoToAlbum(videoURL: url) { success, error in
+                        if success {
+                            kSaveSuccesswShared.show(atView: self.view)
+                        }else{
+                            debugPrint(error)
+                        }
+                    }
+                }
+            }
+        }else{
+            TSImageStoreTool.downloadImageWithProgress(urlString: urlString) { image in
+                if let image = image{
+                    PhotoManagerShared.saveImageToAlbum(image) { success, error in
+                        if success {
+                            kSaveSuccesswShared.show(atView: self.view)
+                        }else{
+                            debugPrint(error)
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    @objc func clickXBtn(){
+        pop()
+    }
+    
+    func clickShare() {
+        guard let currentModel = currentModel else { return }
+        
+        if currentModel.modelType != .example{
+            if kJudgeVip(externalBool: true,vc: self) { return }
+        }
+        
+        let urlString = currentModel.response.resultUrl
+        if currentModel.isVideo {
+            TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
+                if let url = url {
+                    kShareContent(target: self, anyData: url)
+                }
+            }
+        }else{
+            TSImageStoreTool.downloadImageWithProgress(urlString: urlString) { image in
+                if let image = image{
+                    kShareContent(target: self, anyData: image)
+                }
+            }
+        }
+    }
+    
+    func reloadUI() {
+        guard let currentModel = currentModel else { return }
+        kSetBtnVipIcon(btn: bigSaveBtn, show: currentModel.modelType == .example)
+    }
+}
+
+class TSAIPhotoBrowsePageViewVC: TSBasePageVC {
+    override func viewController(at index: Int) -> UIViewController? {
+          guard index >= 0 && index < dataItems.count else { return nil }
+          if let model = dataItems[index] as? TSActionInfoModel  {
+              return TSAIPhotoDetailsBrowserBaseVC.createBrowserVC(with: model,frame: self.view.frame)
+          }
+          return nil
+      }
+    
+    override func indexOfViewController(_ viewController: UIViewController) -> Int? {
+          guard let vc = viewController as? TSAIPhotoDetailsBrowserBaseVC,
+                let index = dataItems.firstIndex(where: { ($0 as? TSActionInfoModel) == vc.model }) else {
+              return nil
+          }
+          return index
+      }
+    
+    override func dealThings() {
+ 
+    }
+}
+
+
+class TSAIPhotoDetailsBrowserBaseVC: TSBaseVC {
+    
+    var model:TSActionInfoModel
+    init(model: TSActionInfoModel) {
+        self.model = model
+        super.init()
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func createView() {
+        setNavBarViewHidden(true)
+    }
+    
+    // 工厂方法
+    static func createBrowserVC(with model: TSActionInfoModel,frame:CGRect) -> TSAIPhotoDetailsBrowserBaseVC {
+        if model.isVideo {
+            return TSAIPhotoDetailsBrowserVideoVC(model: model)
+        }else{
+            return TSAIPhotoDetailsBrowserImageVC(model: model)
+        }
+    }
+    
+}
+
+class TSAIPhotoDetailsBrowserImageVC: TSAIPhotoDetailsBrowserBaseVC {
+    lazy var netWorkImageView: UIImageView = UIImageView.createImageView()
+    lazy var vipImageView: UIImageView = {
+        let vipImageView = UIImageView.createImageView(imageName:"vip_side_icon")
+        vipImageView.contentMode = .scaleToFill
+        vipImageView.isHidden = true
+        return vipImageView
+    }()
+    
+    override func createView() {
+        super.createView()
+        contentView.addSubview(netWorkImageView)
+        netWorkImageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        netWorkImageView.addSubview(vipImageView)
+        vipImageView.snp.makeConstraints { make in
+            make.width.height.equalTo(40)
+            make.top.equalTo(-5)
+            make.trailing.equalTo(5)
+        }
+    }
+    
+    override func dealThings() {
+        if model.modelType == .example {
+            netWorkImageView.image = UIImage(named:model.response.resultUrl)
+        }else{
+            netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder: kPlaceholderImage)
+        }
+        vipImageView.isHidden = !model.response.vip
+    }
+}
+
+class TSAIPhotoDetailsBrowserVideoVC: TSAIPhotoDetailsBrowserBaseVC {
+    
+    var videoPlayerVC: TSAIListVideoPlayerVC?
+    
+    override func createView() {
+        super.createView()
+    }
+    
+    
+    override func dealThings() {
+        self.videoPlayerVC?.view.removeFromSuperview()
+        self.contentView.removeAllSubViews()
+        self.videoPlayerVC = nil
+        self.videoPlayerVC = TSAIListVideoPlayerVC(videoURL: self.model.videoURL)
+        self.view.addSubview(self.videoPlayerVC!.view)
+        self.videoPlayerVC!.setControlsBottom(bottem: -20)
+        self.videoPlayerVC!.view.snp.remakeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        self.videoPlayerVC?.runloppPlay()
+    }
+    
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        self.videoPlayerVC?.runloppPlay()
+    }
+    
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        self.videoPlayerVC?.playPause()
+    }
+
+}

+ 11 - 20
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVideoTimesVC/TSPurchaseVideoTimesVC.swift

@@ -33,7 +33,7 @@ class TSPurchaseVideoTimesVC: TSBaseVC {
     var cancellabel: [AnyCancellable] = []
     var viewModel: TSPurchaseVideoTimesVM = .init()
     var buyPeriod:PremiumPeriod = .year
-    var isHandlePurchaseStateChanged = true //是否处理购买状态变化
+    var isHandlePurchaseStateChanged = false //是否处理购买状态变化
     
     
     lazy var fullVC: UIHostingController<TSPurchaseVideoTimesView> = {
@@ -42,8 +42,8 @@ class TSPurchaseVideoTimesVC: TSBaseVC {
         return vc
     }()
     
-    lazy var alertVC: UIHostingController<TSPurchaseVideoTimesView> = {
-        let vc = UIHostingController(rootView: TSPurchaseVideoTimesView(viewModel: viewModel))
+    lazy var alertVC: UIHostingController<TSPurchaseVideoTimesAlertView> = {
+        let vc = UIHostingController(rootView: TSPurchaseVideoTimesAlertView(viewModel: viewModel))
         vc.view.backgroundColor = .clear
         return vc
     }()
@@ -107,17 +107,11 @@ class TSPurchaseVideoTimesVC: TSBaseVC {
                     TSToastShared.showLoading(text: "Purchasing now".localized,containerView: self.view)
                 case .paySuccess:
                     TSToastShared.hideLoading()
-                 
-                    var loadingText = "Finish".localized
-                    if manager.isVip {
-                        loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized
-                    }
-                    
+                    let loadingText = "购买成功".localized
+                    debugPrint(loadingText)
                     TSToastShared.showToast(text:loadingText)
-                    if manager.isVip {
-                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-                            self.closePage()
-                        }
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+                        self.closePage()
                     }
 
                 case .payFail:
@@ -130,16 +124,13 @@ class TSPurchaseVideoTimesVC: TSBaseVC {
                     TSToastShared.showLoading(text: "Restoring now".localized,containerView: self.view)
                 case .restoreSuccess:
                     TSToastShared.hideLoading()
-//                    let loadingText = manager.isVip ? "Congratulation you have become VIP".localized : "Couldn't Restore Subscription".localized
-                    let loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized
+                    let loadingText = "购买成功".localized
                     debugPrint(loadingText)
                     TSToastShared.showToast(text:loadingText)
-                    if manager.isVip {
-                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
-                            self.closePage()
-                        }
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+                        self.closePage()
                     }
-
+                    
                 case .restoreFail:
                     TSToastShared.hideLoading()
                     let loadingText = (object as? String) ?? "Failed to restore subscribe, please try again".localized

+ 141 - 7
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVideoTimesVC/View/TSPurchaseVideoTimesAlertView.swift

@@ -9,13 +9,147 @@ import SwiftUI
 import SwiftUIX
 
 struct TSPurchaseVideoTimesAlertView :View {
-    @ObservedObject var viewModel: PurchaseViewModel
-    
+    @ObservedObject var viewModel: TSPurchaseVideoTimesVM
+    @State var isExpand: Bool = false
     var body: some View {
-        
-        Text("Unlock All Features".localized)
-            .font(.font(size: 16,weight: .medium))
-            .foregroundColor(.hex("#111111"))
+        VStack {
+            
+            Spacer()
+            
+            VStack {
+                Spacer().frame(height: 24)
+                Text("Limit Reached".localized)
+                    .font(.font(size: 22,weight: .medium))
+                    .foregroundColor(.white)
+                    .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
+                
+                Spacer().frame(height: 16)
+                Text("You've hit your weekly limit. Get more effect credits below.".localized)
+                    .foregroundColor(.white.opacity(0.7))
+                    .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
+                
+                Spacer().frame(height: 15)
+                VStack(alignment: .leading, spacing: 20, content: {
+                    TSPurchaseVideoTimesCellView(type: .purchase(.videoNum1), selectedType: $viewModel.selectedType)
+                        .onTapGesture {
+                            viewModel.selectedType = .purchase(.videoNum1)
+                        }
+                    ZStack(alignment: .topTrailing) {
+                        TSPurchaseVideoTimesCellView(type: .purchase(.videoNum2), selectedType: $viewModel.selectedType)
+                            .onTapGesture {
+                                viewModel.selectedType = .purchase(.videoNum2)
+                            }
+                        TSPurchaseVideoTimesRecView()
+                            .offset(x:-30,y:-14)
+                    }
+                    TSPurchaseVideoTimesCellView(type: .purchase(.videoNum3), selectedType: $viewModel.selectedType)
+                        .onTapGesture {
+                            viewModel.selectedType = .purchase(.videoNum3)
+                        }
+                }).multilineTextAlignment(.center).font(.font(size: 16,weight:.regular)).foregroundColor(.white)
+                
+                Spacer().frame(height: 44)
+                
+                
+                Button {
+                    viewModel.buyPublisher.send(true)
+                } label: {
+                    ZStack {
+                        Image(.purchaseVideoTimesBtnbg)
+                        Text("Purchase".localized)
+                            .font(.font(size: 16,weight: .medium))
+                            .foregroundColor(.white)
+                    }.frame(maxWidth: .infinity ,minHeight: 48.0,maxHeight: 48.0)
+                }
+                
+                
+                VStack{
+                    Spacer().frame(height: 15)
+                    Button {
+                        withAnimation(.easeInOut(duration: 0.3)) {
+                            isExpand.toggle()
+                        }
+                    } label: {
+                        HStack(spacing: 4) {
+                            Text("View Credit Rules".localized)
+                                .font(.font(size: 12,weight: .regular))
+                                .foregroundColor(.white.opacity(0.7))
+                            Image(isExpand ? .chatUpArrow : .chatDownArrow)
+                        }
+                    }
+                }
+                
+                if isExpand {
+                    
+                    Spacer().frame(height: 10)
+                    
+                    VStack(alignment: .leading, spacing: 8, content: {
+                        TSPurchaseVideoTextLineView(image: .purchaseVideoTimesCheck, text: "Only VIP can purchase video effect credits".localized)
+                        TSPurchaseVideoTextLineView(image: .purchaseVideoTimesCheck, text: "Credits can be applied to all video generations".localized)
+                        TSPurchaseVideoTextLineView(image: .purchaseVideoTimesCheck, text: "Credits never expire and can be purchased repeatedly".localized)
+                        TSPurchaseVideoTextLineView(image: .purchaseVideoTimesCheck, text: "All unused credits will be lost if the app is uninstalled".localized)
+                    })
+                    .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
+                    
+                    Spacer().frame(height: 24 + k_Height_safeAreaInsetsBottom())
+                }else{
+                    Spacer().frame(height: k_Height_safeAreaInsetsBottom())
+                }
+
+            }
+            .padding(.horizontal,16)
+            .background(
+                Color.hex("#261840").cornerRadius([.topLeading,.topTrailing], 20)
+            )
+
+        }
+        .ignoresSafeArea()
+    }
+}
+
+
+struct TSPurchaseVideoTimesAler1tView :View {
+    @State var isExpand: Bool = false
+    var body: some View {
+        VStack {
+
+            Spacer()
+            
+            VStack {
+                Spacer().frame(height: 24)
+                Text("Limit Reached".localized)
+                
+                Spacer().frame(height: 24)
+                
+                VStack{
+                    Spacer().frame(height: 15)
+                    Button {
+                        isExpand = !isExpand
+                    } label: {
+                        HStack(spacing: 4) {
+                            Text("View Credit Rules".localized)
+                                .font(.font(size: 12,weight: .regular))
+                                .foregroundColor(.white.opacity(0.7))
+                            Image(isExpand ? .chatUpArrow : .chatDownArrow)
+                        }
+                    }
+                    Spacer().frame(height: k_Height_safeAreaInsetsBottom())
+                }
+                
+                if isExpand {
+                    VStack(alignment: .leading, spacing: 8, content: {
+                        Text("View Credit Rules1".localized)
+                        Text("View Credit Rules2".localized)
+                        Text("View Credit Rules3".localized)
+                    })
+                    .padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
+                    
+                    Spacer().frame(height: 24 + k_Height_safeAreaInsetsBottom())
+                }
+
+            }
+            .padding(.horizontal,16)
+        }
+        .ignoresSafeArea()
     }
-    
 }

+ 16 - 12
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVideoTimesVC/View/TSPurchaseVideoTimesView.swift

@@ -43,10 +43,14 @@ struct TSPurchaseVideoTimesView :View {
                             .onTapGesture {
                                 viewModel.selectedType = .purchase(.videoNum1)
                             }
-                        TSPurchaseVideoTimesCellView(type: .purchase(.videoNum2), selectedType: $viewModel.selectedType)
-                            .onTapGesture {
-                                viewModel.selectedType = .purchase(.videoNum2)
-                            }
+                        ZStack(alignment: .topTrailing) {
+                            TSPurchaseVideoTimesCellView(type: .purchase(.videoNum2), selectedType: $viewModel.selectedType)
+                                .onTapGesture {
+                                    viewModel.selectedType = .purchase(.videoNum2)
+                                }
+                            TSPurchaseVideoTimesRecView()
+                                .offset(x:-12,y:-9)
+                        }
                         TSPurchaseVideoTimesCellView(type: .purchase(.videoNum3), selectedType: $viewModel.selectedType)
                             .onTapGesture {
                                 viewModel.selectedType = .purchase(.videoNum3)
@@ -68,6 +72,8 @@ struct TSPurchaseVideoTimesView :View {
                     }
                     
                     Spacer().frame(height: 24 + k_Height_safeAreaInsetsBottom())
+                    
+                    Text("").frame(height: 1.0)
                 }
                 .padding(.horizontal,16)
                 .background(
@@ -79,6 +85,7 @@ struct TSPurchaseVideoTimesView :View {
                 .offset(x:0,y:-107)
             }
         }
+        .ignoresSafeArea()
     }
 }
                        
@@ -90,7 +97,7 @@ struct TSPurchaseVideoTextLineView: View {
        HStack(alignment: .top, spacing: 4) {
            Image(image).resizable().frame(width: 24, height: 24)
            Text(text).lineLimit(2).multilineTextAlignment(.leading).font(.font(size: 16,weight:.regular)).foregroundColor(.white)
-       }.frame(height: 38)
+       }.frame(height: 40)
    }
 }
 struct TSPurchaseVideoTimes1View :View {
@@ -144,15 +151,12 @@ struct TSPurchaseVideoTimesCellView: View {
 
 
 struct TSPurchaseVideoTimesRecView: View {
-    var save:String
     var body: some View {
-    
-        HStack(spacing: 0) {
-            Text(String(format: "%d%% Picked".localized, 90)).lineLimit(2).multilineTextAlignment(.leading).font(.font(size: 11,weight:.medium)).foregroundColor(Color.hex("#111111"))
-        }
+
+        Text(String(format: "%d%% Picked".localized, 90)).lineLimit(2).multilineTextAlignment(.leading).font(.font(size: 11,weight:.medium)).foregroundColor(Color.hex("#111111"))
+        .frame(height: 18) // 设置高度
         .padding(EdgeInsets(top: 0, leading: 6, bottom: 0, trailing: 6))
         .background(Color.hex("#FECB34"))
-        .frame(height: 18) // 设置高度
-        .cornerRadius([.topLeading, .topTrailing, .bottomLeading, .bottomTrailing], 16.0)
+        .cornerRadius(9)
     }
 }

+ 2 - 1
AIEmoji/Business/TSSetingVC/SetingVC/TSSetingViewModel.swift

@@ -97,7 +97,8 @@ class TSSetingViewModel: ObservableObject {
     }
     
     func purchaseVideoTimesVC(parent: UIViewController) {
-        kPushVC(target: parent, modelVC: TSPurchaseVideoTimesVC(isShowAlertModel: false))
+        kPresentModalVC(target: parent, modelVC: TSPurchaseVideoTimesVC(isShowAlertModel: true))
+//        kPresentModalVC(target: parent, modelVC: TSPurchaseVideoTimesVC(isShowAlertModel: false))
     }
     
     

+ 17 - 13
AIEmoji/Business2/DisCover/TSGenerateHistoryVC/TSGenerateHistoryVC.swift

@@ -9,7 +9,7 @@ import RealmSwift
 
 class TSGenerateHistoryVC: TSBaseVC {
 
-    var listModelArray = List<TSDBActionInfoModel>()//惰性加载特性
+    var listModelArray:[TSActionInfoModel] = []
     //###################################### 导航栏 view ######################################
     lazy var vipBtn: UIButton = {
        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
@@ -180,8 +180,11 @@ class TSGenerateHistoryVC: TSBaseVC {
     }
     
     @objc func updateDataView(){
-        listModelArray = dbHistory.listModels//惰性加载特性
-        updateView()
+        dbHistory.getModelList(completion: { [weak self] dataArray in
+            guard let self = self else { return }
+            listModelArray = dataArray
+            updateView()
+        })
     }
     
 
@@ -221,8 +224,8 @@ extension TSGenerateHistoryVC: UICollectionViewDataSource ,UICollectionViewDeleg
     public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
-        if let cell = cell as? TSGenerateHistoryCell ,let dbModel = listModelArray[safe:indexPath.row]{
-            cell.dataModel = dbModel.getModel()
+        if let cell = cell as? TSGenerateHistoryCell ,let dbModel = listModelArray.safeObj(At:indexPath.row){
+            cell.dataModel = dbModel
             cell.buttonTapped = { [weak self] cmd in
                 self?.handelCellCmd(cmd: cmd,indexPath: indexPath)
             }
@@ -232,14 +235,15 @@ extension TSGenerateHistoryVC: UICollectionViewDataSource ,UICollectionViewDeleg
     }
 
     public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
-        guard let selectedModel = listModelArray[safe:indexPath.row] else { return }
-        let filteredResults = listModelArray.filter("status == %@", "success")//直接过滤List(返回Results类型)
-        let filteredList = List<TSDBActionInfoModel>()
-        filteredList.append(objectsIn: filteredResults)
+        guard let selectedModel = listModelArray.safeObj(At:indexPath.row) else { return }
+        let filteredResults = listModelArray.filter({$0.status == "success"})
+        let startIndex = filteredResults.firstIndex(of: selectedModel) ?? 0
+        
+//        let browseVC = TSAIPhotoBrowseVC()
+//        browseVC.dataModelArray = filteredList
+//        browseVC.currentIndex = startIndex
         
-        let browseVC = TSAIPhotoBrowseVC()
-        browseVC.dataModelArray = filteredList
-        browseVC.currentIndex = filteredList.firstIndex(of: selectedModel) ?? 0
+        let browseVC = TSAIPhotoBrowsePageVC(dataItems: filteredResults, startIndex: startIndex)
         browseVC.deleteComplete = { [weak self]  deleteModel in
             guard let self = self else { return }
             dbHistory.deleteListModel(uuid: deleteModel.uuid)
@@ -265,7 +269,7 @@ extension TSGenerateHistoryVC: UICollectionViewDataSource ,UICollectionViewDeleg
 
 extension TSGenerateHistoryVC{
     func handelCellCmd(cmd:String,indexPath: IndexPath){
-        if let currentActionInfoModel = listModelArray[safe:indexPath.row]{
+        if let currentActionInfoModel = listModelArray.safeObj(At:indexPath.row){
             if cmd == "delete_task_expired" {
                 dbHistory.deleteListModel(id: currentActionInfoModel.id)
                 updateDataView()

+ 4 - 5
AIEmoji/Common/Purchase/TSPurchaseManager+Free.swift

@@ -11,12 +11,11 @@ extension PurchaseManager {
     
     /// 使用一次免费次数
     func useOnceForFree(type: VipFreeNumType) {
-        if isVip {
-            //成为会员后的额度
+        if freeNum(type: type) > 0 {
+            saveForFreeNum(type: type) //非会员的免费次数
+        }else{
             saveForDayGeneratedNum(type: type)
             saveForVipGeneratedNum(type: type)
-        }else{
-            saveForFreeNum(type: type) //非会员的免费次数
         }
     }
     
@@ -107,7 +106,7 @@ extension PurchaseManager {
         if isVip == true {
             return true
         } else {
-            if let freeNum = getFreeDict()[type.rawValue], freeNum > 0 {
+            if freeNum(type: type) > 0 {
                 return true
             }
         }

+ 8 - 8
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -34,8 +34,8 @@ public class PurchaseManager: NSObject {
             PurchaseProduct(productId: "113", period: .week(.weekPromotional1)),
             
             PurchaseProduct(productId: "201", period: .purchase(.videoNum1)),
-            PurchaseProduct(productId: "201", period: .purchase(.videoNum1)),
-            PurchaseProduct(productId: "201", period: .purchase(.videoNum1)),
+            PurchaseProduct(productId: "202", period: .purchase(.videoNum1)),
+            PurchaseProduct(productId: "203", period: .purchase(.videoNum1)),
         ]
     }()
 
@@ -121,9 +121,9 @@ public class PurchaseManager: NSObject {
     }
 
     @objc public var isVip: Bool {
-//#if DEBUG
-//        return true
-//#endif
+#if DEBUG
+        return vipType != .none
+#endif
         guard let expiresDate = expiredDate else {
             return false
         }
@@ -135,9 +135,9 @@ public class PurchaseManager: NSObject {
     }
 
     public var vipType: PremiumPeriod {
-//#if DEBUG
-//        return PremiumPeriod.none
-//#endif
+#if DEBUG
+        return PremiumPeriod.week(.week)
+#endif
         guard isVip, let type = vipInformation["type"] as? String else {
             return .none
         }