// // TSDiscoverVC.swift // AIEmoji // // Created by 100Years on 2025/6/23. // class TSDiscoverVC: TSBaseVC { let viewModel = kTSDiscoverVM var hintBaseVC:TSAIListHintBaseVC = TSAIListHintBaseVC(config: .defaultConfig) lazy var photoPickerManager: TSPhotoPickerManager = TSPhotoPickerManager(viewController: self) // lazy var vipBtn: UIButton = { // let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self] in // guard let self = self else { return } // if kPurchaseCountDownTime.isCountDown { // kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false)) // }else{ // TSPurchaseVC.show(target: self) // } // } // vipBtn.isHidden = true // return vipBtn // }() // // lazy var purchaseCountdownView : TSPurchaseCountdownView = { // let purchaseCountdownView = TSPurchaseCountdownView() // purchaseCountdownView.clickBlock = { [weak self] in // guard let self = self else { return } // kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false)) // } // purchaseCountdownView.isHidden = true // return purchaseCountdownView // }() // lazy var navBarView: TSBaseNavContentBarView = { // let navBarView = TSBaseNavContentBarView() // // let label = UILabel.createLabel(text: "Discover".localized,font: .font(size: 22,weight: .semibold),textColor: .white) // label.addShadow(shadowColor: UIColor.black.cgColor, shadowOffset: CGSize(width: 2, height: 2), shadowRadius: 2, shadowOpacity: 0.3) // navBarView.barView.addSubview(label) // label.snp.makeConstraints { make in // make.centerY.equalToSuperview() // make.leading.equalTo(17.0) // } // // // let stackView:UIStackView = UIStackView() // stackView.spacing = 8 // navBarView.barView.addSubview(stackView) // stackView.addArrangedSubview(vipBtn) // stackView.addArrangedSubview(purchaseCountdownView) // stackView.snp.makeConstraints { make in // make.centerY.equalToSuperview() // make.trailing.equalTo(-16) // } // vipBtn.snp.makeConstraints { make in // make.width.height.equalTo(24) // } // // purchaseCountdownView.snp.makeConstraints { make in // make.height.equalTo(24) // } // // // return navBarView // }() lazy var collectionView: TSBaseCollectionView = { let collectionViewLayout = UICollectionViewFlowLayout() let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) collectionView.delegate = self collectionView.dataSource = self for cases in TSDiscoverViewStyle.allCases { collectionView.register(cases.cell, forCellWithReuseIdentifier: String(describing: cases.cell)) } collectionView.register(TSDiscoverHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "TSDiscoverHeaderView") return collectionView }() override func viewDidLoad() { super.viewDidLoad() ClickEvent.logEvent(type: .discoverTab) } override func createView() { addNormalNavBarView() // navBarContentView.addSubview(navBarView) // navBarView.snp.makeConstraints { make in // make.edges.equalToSuperview() // } contentView.snp.updateConstraints { make in make.top.equalTo(0) } contentView.addSubview(collectionView) collectionView.snp.makeConstraints { make in make.edges.equalToSuperview() } TSDiscoverStyleMoreBaseCell.collectionView = collectionView } override func dealThings() { // NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil) // updateVipView() // NotificationCenter.default.addObserver(self, selector: #selector(checkkPurchaseCountDownTime), name: .kCloseTSPurchasePromotionalVC, object: nil) // checkkPurchaseCountDownTime() } // @objc func updateVipView() { // kMainAsync{ // self.vipBtn.isHidden = PurchaseManager.default.isVip // self.checkkPurchaseCountDownTime() // } // } // // @objc func checkkPurchaseCountDownTime(){ // if kPurchaseCountDownTime.isCountDown { // self.purchaseCountdownView.isHidden = false // kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in // guard let self = self else { return } // if end { // self.purchaseCountdownView.isHidden = true // }else{ // self.purchaseCountdownView.minLabel.text = minutes // self.purchaseCountdownView.secLabel.text = seconds // } // } // }else{ // self.purchaseCountdownView.isHidden = true // } // } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // checkkPurchaseCountDownTime() } } extension TSDiscoverVC: UICollectionViewDataSource ,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{ func numberOfSections(in collectionView: UICollectionView) -> Int { return viewModel.discoverDatas.count } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if let secModel = viewModel.discoverDatas.safeObj(At:section){ return secModel.items.count } return 0 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if let secModel = viewModel.discoverDatas.safeObj(At:indexPath.section),let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing:secModel.style.cell), for: indexPath) as? TSDiscoverBaseCell, let item = secModel.items.safeObj(At:indexPath.row){ cell.items = item cell.clickBlock = { [weak self] model in guard let self = self else { return } if let secModel = viewModel.discoverDatas.safeObj(At:indexPath.section) { TSDiscoverVC.clickCell(target: self,indexPath: indexPath, itemModel:model,secModel: secModel) } } cell.clickSpecialBlock = { [weak self] cmd,data in guard let self = self else { return } clickSpecialBlock(cmd: cmd, data: data) } return cell } return UICollectionViewCell() } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if let secModel = viewModel.discoverDatas.safeObj(At:indexPath.section), kind == UICollectionView.elementKindSectionHeader, let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "TSDiscoverHeaderView", for: indexPath) as? TSDiscoverHeaderView{ header.sectionModel = secModel header.clickBlock = { [weak self] model in guard let self = self else { return } clickHeader(indexPath: indexPath,model: model) } return header } return UICollectionReusableView() } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize{ if let secModel = viewModel.discoverDatas.safeObj(At:indexPath.section) { return secModel.style.itemSize } return .zero } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets{ if let secModel = viewModel.discoverDatas.safeObj(At:section) { var sectionEdge = UIEdgeInsets(top: 0, left: kDiscoverSection.left, bottom: 0, right: kDiscoverSection.right) if secModel.title.isEmpty,section != 0 { sectionEdge = UIEdgeInsets(top: 20, left: kDiscoverSection.left, bottom: 0, right: kDiscoverSection.right) } if section == viewModel.discoverDatas.count-1 { sectionEdge = UIEdgeInsets(top: sectionEdge.top, left: sectionEdge.left, bottom: sectionEdge.bottom+20, right: sectionEdge.right) } return sectionEdge } return .zero } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { if let secModel = viewModel.discoverDatas.safeObj(At:section),secModel.title.count > 0 { return CGSize(width: k_ScreenWidth, height: kDiscoverSectionH) } return .zero } // 当cell即将显示时恢复播放 func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? TSDiscoverBaseCell { cell.willDisplay(indexPath: indexPath) } } // 当cell结束显示时暂停播放 func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if let cell = cell as? TSDiscoverBaseCell { cell.didEndDisplaying(indexPath: indexPath) } } } //extension TSDiscoverVC: UIScrollViewDelegate { // // 开始拖拽(用户开始滚动) // func scrollViewDidScroll(_ scrollView: UIScrollView) { //// dePrint("scrollView.contentOffset.y=\(scrollView.contentOffset.y)") // // let height:CGFloat = 50 + k_Nav_Height // //// let alpha = scrollView.contentOffset.y/height //// navBarView.backgroundColor = .mainBg.withAlphaComponent(alpha) // // navBarView.backgroundColor = scrollView.contentOffset.y >= height ? .mainBg : .clear // } //} //extension TSDiscoverVC: UIScrollViewDelegate { // // 开始拖拽(用户开始滚动) // func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { // print("滚动开始") // NotificationCenter.default.post(name: .kDiscoverScrollViewWillBegin, object: nil) // } // // // 结束拖拽(用户手指离开屏幕) // func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { // if !decelerate { // print("滚动完全停止(无减速动画)") // NotificationCenter.default.post(name: .kDiscoverScrollViewEndDecelerating, object: nil) // } // } // // // 结束减速(滚动完全停止) // func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { // print("滚动完全停止") // NotificationCenter.default.post(name: .kDiscoverScrollViewEndDecelerating, object: nil) // } // // // 以下方法组合可以准确判断滚动是否真正结束 // func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { // print("编程触发的滚动动画结束") // NotificationCenter.default.post(name: .kDiscoverScrollViewEndDecelerating, object: nil) // } //} extension TSDiscoverVC { func clickHeader(indexPath:IndexPath,model:TSDiscoverSectionModel) { kPushVC(target: self, modelVC: TSDiscoverStyleMoreVC(sectionModel: model)) } func clickSpecialBlock(cmd:String,data:Any?) { if TSGenerateBasePhotoOperationQueue.isAvailabilityHandle(view: self.view) { return } if cmd == "ptv" { kPushVC(target: self, modelVC:TSAIDiyVideoVC(diyVideoType: 0)) }else if cmd == "ttv" { kPushVC(target: self, modelVC:TSAIDiyVideoVC(diyVideoType: 1)) } } static func clickCell(target:UIViewController,indexPath:IndexPath,itemModel:TSDiscoverItemModel,secModel:TSDiscoverSectionModel) { if itemModel.style.isInterceptMultipleGenerations, TSGenerateBasePhotoOperationQueue.isAvailabilityHandle(view: target.view) { return } var style = itemModel.style if style == .photoLive, let animationModel = itemModel.viewModel as? TSDiscoverAnimationItemVM, animationModel.style == .video { style = .videoV2 } dePrint("\(style)") switch style{ case .ageOld, .ageChild, .oldPhoto, .eyeOpen, .pretty, .photoLive, .photoQuality, .catTohuman,.process: kPushVC(target: target, modelVC: TSAIUploadPhotoBaseVC(titleString: itemModel.name, generatorStyle: itemModel.style,disCoverItemModel: itemModel)) case .photoExpand: kPushVC(target: target, modelVC: TSAIExpandImageVC(upLoadImage: nil)) case .futureBaby: kPushVC(target: target, modelVC: TSFutureBabyVC()) case .changeEmote: TSDiscoverVC.enterSelectPhotos(target: target,style: itemModel.style) { image in kPushVC(target: target, modelVC: TSAIChangeEmoteVC(upLoadImage: image, style: .changeEmote)) } break case .changehairColor: TSDiscoverVC.enterSelectPhotos(target: target,style: itemModel.style) { image in kPushVC(target: target, modelVC: TSAIChangeEmoteVC(upLoadImage: image, style: .changehairColor)) } break case .changehair: TSDiscoverVC.enterSelectPhotos(target: target,style: itemModel.style) { image in kPushVC(target: target, modelVC: TSAIChangeEmoteVC(upLoadImage: image, style: .changehair)) } case .ttp: kPushVC(target: target, modelVC: TSTTPInputVC()) case .chat: let vc = TSChatViewController() vc.viewModel.uiStyle = .chat kPushVC(target: target, modelVC: vc) case .ptp,.videoV2: if let generateModel = itemModel.generateModel{ kPushVC(target: target, modelVC: TSPTPUploadImageVC(itemModel:itemModel,generateModel: generateModel, sectionModel: secModel)) } default: break } } } extension TSDiscoverVC{ static var hintBaseVC:TSAIListHintBaseVC? static var photoPickerManager:TSPhotoPickerManager? static func enterSelectPhotos( target:UIViewController, style:TSFuncStyle, hintType:Int = 0, interceptSelectedPictureBlock:((UIImage) -> Bool)? = nil, complete: @escaping (UIImage)->Void) { let userDefaultsKey = style.getHintKey(hintType: hintType) if userDefaultsKey.count == 0 || style == .ptp { self.pickSinglePhoto(target:target,interceptSelectedPictureBlock: interceptSelectedPictureBlock,complete:complete) }else{ TSAIListHintBaseVC.userDefaultsKey = userDefaultsKey if TSAIListHintBaseVC.isShowUploadImageHint{ TSAIListHintBaseVC.isShowUploadImageHint = false self.presentModalHintVC(target:target,config:style.getConfig(hintType: hintType),complete:complete) }else { self.pickSinglePhoto(target:target,interceptSelectedPictureBlock: interceptSelectedPictureBlock,complete:complete) } } } static func presentModalHintVC(target:UIViewController,config:TSAIListHintBaseVC.Config,complete:@escaping (UIImage)->Void){ let hintBaseVC = TSAIListHintBaseVC(config: config) hintBaseVC.clickUpImageHandle = { image in if let image = image { complete(image) }else{ dePrint("图片异常") } kDelayMainShort { Self.hintBaseVC?.dismissPageVC() Self.hintBaseVC = nil } } kPresentModalVC(target: target, modelVC: hintBaseVC,transitionStyle: .crossDissolve) Self.hintBaseVC = hintBaseVC } static func pickSinglePhoto(target:UIViewController,interceptSelectedPictureBlock:((UIImage) -> Bool)? = nil,complete: @escaping (UIImage)->Void) { let photoPickerManager = TSPhotoPickerManager(viewController: target) photoPickerManager.interceptSelectedPictureBlock = interceptSelectedPictureBlock photoPickerManager.pickCustomSinglePhoto() { image, errorString in if let errorString = errorString { TSToastShared.showToast(text: errorString) }else if let image = image { complete(image) }else{ dePrint("图片异常") } kDelayMainShort { Self.photoPickerManager?.dismissPageVC() Self.photoPickerManager = nil } } Self.photoPickerManager = photoPickerManager } } extension TSDiscoverVC:TSTabBarControllerProtocol { func tabBarDoubleTap(_ tabbar: UITabBarController){ collectionView.setContentOffset(CGPoint(x: 0, y: 0), animated: true) } }