123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- //
- // TSPTPInputVC.swift
- // AIEmoji
- //
- // Created by 100Years on 2025/4/7.
- //
- //import IQKeyboardManagerSwift
- import PhotosUI
- class TSPTPInputVC: TSBaseVC {
- lazy var viewModel: TSPTPInputVM = {
- let viewModel = TSPTPInputVM()
- viewModel.isCanGennerateBlock = { [weak self] isCan in
- guard let self = self else { return }
- submitBtn.isEnabled = isCan
- }
- return viewModel
- }()
-
- lazy var photoPickerManager: TSPhotoPickerManager = {
- let photoPickerManager = TSPhotoPickerManager(viewController: self)
- return photoPickerManager
- }()
-
- //###################################### 导航栏 view ######################################
- lazy var vipBtn: UIButton = {
- let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self] in
- guard let self = self else { return }
- TSPurchaseVC.show(target: self) {}
- }
- return vipBtn
- }()
-
- lazy var navBarView: TSBaseNavContentBarView = {
- let navBarView = TSBaseNavContentBarView()
-
- let titleImageView = UIImageView.createImageView(imageName: "nav_title_pic",contentMode: .scaleToFill)
- navBarView.barView.addSubview(titleImageView)
- titleImageView.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalTo(16)
- }
-
- // let keyboardBtn = UIButton.createButton(image: UIImage(named: "keyboard")) { [weak self] in
- // guard let self = self else { return }
- // kPresentModalVC(target: self, modelVC: TSWallpaperVC())
- // }
- // navBarView.barView.addSubview(keyboardBtn)
- // keyboardBtn.snp.makeConstraints { make in
- // make.centerY.equalToSuperview()
- // make.trailing.equalTo(-16)
- // make.width.height.equalTo(24)
- // }
-
- navBarView.barView.addSubview(vipBtn)
- vipBtn.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.trailing.equalTo(-16)//(-60)
- make.width.height.equalTo(24)
- }
-
- return navBarView
- }()
-
- //###################################### cusStackView ######################################
- lazy var cusStackView: TSCustomStackView = {
- let cusStackView = TSCustomStackView(axis: .vertical,spacing: 0)
- cusStackView.scrollView.isScrollEnabled = false
- return cusStackView
- }()
- // //###################################### 入口 view ######################################
- //
- // let bannerY:CGFloat = 17
- // let bannerW:CGFloat = 166*kDesignScale
- // let bannerH:CGFloat = 117*kDesignScale
- // lazy var textToPhotoBannerBtn: UIButton = {
- // let textToPhotoBannerBtn = UIButton.createButton(backgroundImage: UIImage(named: "textToPhoto_banner"))
- // textToPhotoBannerBtn.addTarget(self, action: #selector(clickTextToPhoto), for: .touchUpInside)
- // textToPhotoBannerBtn.frame = CGRect(x: 16, y: bannerY, width: bannerW, height: bannerH)
- //
- // let label = UILabel.createLabel(text: "Text ➡️ Photo".localized,font: .font(name:.PoppinsBlackItalic,size: 16),textColor: .white)
- // textToPhotoBannerBtn.addSubview(label)
- // label.snp.makeConstraints { make in
- // make.top.equalTo(12)
- // make.leading.equalTo(8)
- // make.height.equalTo(24)
- // }
- //
- // let button = UIButton.createButton(title:"Try Now".localized,backgroundColor:.white,font: .font(size: 11),titleColor: "#ED69AA".uiColor,corner: 9)
- // button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 6)
- // textToPhotoBannerBtn.addSubview(button)
- // button.snp.makeConstraints { make in
- // make.top.equalTo(44)
- // make.leading.equalTo(8)
- // make.height.equalTo(18)
- // }
- //
- // return textToPhotoBannerBtn
- // }()
- //
- // lazy var textToEmojiBannerBtn: UIButton = {
- // let textToEmojiBannerBtn = UIButton.createButton(backgroundImage: UIImage(named: "textToEmoji_banner"))
- // textToEmojiBannerBtn.addTarget(self, action: #selector(clickTextToEmoji), for: .touchUpInside)
- // let x = textToPhotoBannerBtn.x + textToPhotoBannerBtn.width + 11.0
- // textToEmojiBannerBtn.frame = CGRect(x: x, y: bannerY, width: bannerW, height: bannerH)
- //
- // let color:UIColor = "#7855D6".uiColor
- // let label = UILabel.createLabel(text: "Text ➡️ Emoji".localized,font: .font(name:.PoppinsBlackItalic,size: 16),textColor: color)
- // textToEmojiBannerBtn.addSubview(label)
- // label.snp.makeConstraints { make in
- // make.top.equalTo(12)
- // make.leading.equalTo(8)
- // make.height.equalTo(24)
- // }
- //
- // let button = UIButton.createButton(title:"Try Now".localized,backgroundColor:color,font: .font(size: 11),titleColor: "#D0D5FF".uiColor,corner: 9)
- // button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 6)
- // textToEmojiBannerBtn.addSubview(button)
- // button.snp.makeConstraints { make in
- // make.top.equalTo(44)
- // make.leading.equalTo(8)
- // make.height.equalTo(18)
- // }
- //
- // return textToEmojiBannerBtn
- // }()
- //
- //
- // lazy var entranceView: UIView = {
- // let entranceView = UIView()
- // entranceView.addSubview(textToPhotoBannerBtn)
- // entranceView.addSubview(textToEmojiBannerBtn)
- // return entranceView
- // }()
-
- //###################################### 上传图片 ######################################
- lazy var uploadView: TSPTPUploadView = {
- let uploadView = TSPTPUploadView()
- uploadView.clickHandel = { [weak self] index in
- guard let self = self else { return }
-
- if index == 0 {//删除
- viewModel.upLoadImage = nil
- uploadView.upLoadImage = nil
- }else{//添加
- if TSAIAgeImageHintVC.isShowUploadImageHint{
- TSAIAgeImageHintVC.isShowUploadImageHint = false
- presentModalHintVC()
- }else {
- pickSinglePhoto()
- }
- }
- }
- return uploadView
- }()
-
-
- func pickSinglePhoto() {
- photoPickerManager.pickSinglePhoto { [weak self] image,phAsset in
- guard let self = self else { return }
- handleSinglePhoto(image: image, phAsset: phAsset)
- }
- }
-
- func handleSinglePhoto(image:UIImage?,phAsset:PHAsset?){
- let maxSize = 10 * 1024 * 1024
-
- if let image = image,let phAsset = phAsset {
- // 方法2:异步获取详细大小(不阻塞主线程)
- TSPhotoSizeHelper.getImageFileSizeAsync(asset: phAsset) {[weak self] size in
- guard let self = self else { return }
-
- let mbSize = Double(size) / (1024 * 1024)
- print("精确大小: \(mbSize) MB,size = \(size)")
- if size > maxSize {
- TSToastShared.showToast(text: "Photo must be smaller than 10MB.".localized)
- }else{
- viewModel.upLoadImage = image
- uploadView.upLoadImage = image
- }
- }
- }else if let image = image {
- if image.isLargerThan(byteSize: maxSize) {
- TSToastShared.showToast(text: "Photo must be smaller than 10MB.".localized)
- }else{
- viewModel.upLoadImage = image
- uploadView.upLoadImage = image
- }
- }
- }
-
-
- //###################################### 选择风格 ######################################
- lazy var selectStyleView: TSPTPSelectStyleView = {
- let selectStyleView = TSPTPSelectStyleView()
- selectStyleView.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
- selectStyleView.dataArray = viewModel.ptpStyleModels
- selectStyleView.clickHandle = { [weak self] model in
- guard let self = self else { return }
- viewModel.selectedPTPStyleModel = model
- updateVipView()
- updateTextFiledView()
- }
- return selectStyleView
- }()
-
-
- //###################################### 输入框 ######################################
- private let maxLength = 200 // 最大长度限制
- lazy var customTextView: TSPlaceholderTextView = {
- let customTextView = TSPlaceholderTextView(
- placeholder: "Please describe your photo".localized,
- text: "",
- font: .font(size: 14),
- textColor: .white,
- backgroundColor: .clear
- )
- customTextView.verticalAlignment = .center
- customTextView.delegate = self
- customTextView.returnKeyType = .send
- return customTextView
- }()
-
- lazy var clearBtn: UIButton = {
- let clearBtn = UIButton.createButton(
- image: UIImage(named: "clear_text")
- )
- { [weak self] in
- guard let self = self else { return }
- customTextView.text = ""
- }
- clearBtn.isHidden = true
- return clearBtn
- }()
-
- var promptTextViewH:CGFloat = 84.0
- lazy var promptTextView:UIView = {
- let promptTextView = UIView()
- promptTextView.clipsToBounds = true
- let bgView = UIView()
- bgView.backgroundColor = "#333333".uiColor
- bgView.cornerRadius = 16.0
- promptTextView.addSubview(bgView)
- bgView.snp.makeConstraints { make in
- make.edges.equalTo(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
- }
-
- bgView.addSubview(customTextView)
- bgView.addSubview(clearBtn)
-
- customTextView.snp.makeConstraints { make in
- make.top.bottom.equalTo(0)
- make.centerY.equalToSuperview()
- make.leading.equalTo(12.0)
- make.trailing.equalTo(-32)
- }
-
- clearBtn.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.width.height.equalTo(16.0)
- make.trailing.equalTo(-12)
- }
-
- return promptTextView
- }()
- //###################################### 集合视图 ######################################
- let collectionViewBtootm:CGFloat = 80
- lazy var collectionComponent: TSCollectionViewComponent = {
- let layout = UICollectionViewFlowLayout()
- let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
- cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
-
-
- // 禁用自动 contentInset 调整
- if #available(iOS 11.0, *) {
- cp.collectionView.contentInsetAdjustmentBehavior = .never
- } else {
- automaticallyAdjustsScrollViewInsets = false
- }
-
- cp.sectionActionHandler = { [weak self] cellCp, indexPath in
- guard let self = self else { return }
- if let cmd = cellCp as? String, cmd == "delete" {
- showCustomAlert(message: "Are you sure to delete".localized, deleteHandler: {
- self.viewModel.removeAllHistoryList()
- self.collectionComponent.clear()
- self.collectionComponent.reloadView(with: self.viewModel.colDataArray)
- })
- }
- }
-
- cp.itemDidSelectedHandler = { [weak self] (object, indexPath) in
- guard let self = self else { return }
-
- if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel{
- var dataModelArray:[TSGenmojiModel] = []
- for itemModel in sections.items {
- dataModelArray.append(itemModel.dataModel)
- }
-
- let browseVC = TSAIPhotoBrowseVC()
- browseVC.dataModelArray = dataModelArray
- browseVC.currentIndex = indexPath.item
- kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
- }
- }
- return cp
- }()
-
- //###################################### 按钮 ######################################
- lazy var submitBtn: UIButton = {
- let submitBtn = kCreateNormalSubmitBtn(title: getVipText()) { [weak self] in
- guard let self = self else { return }
- generateImage()
- }
- submitBtn.cornerRadius = 24.0
- submitBtn.isEnabled = false
- return submitBtn
- }()
- override func createView() {
-
- navBarContentView.addSubview(navBarView)
- navBarView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
- contentView.addSubview(collectionComponent.collectionView)
- collectionComponent.collectionView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
-
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickView))
- tapGesture.cancelsTouchesInView = false
- view.addGestureRecognizer(tapGesture)
- collectionComponent.clear()
- collectionComponent.reloadView(with:viewModel.colDataArray)
-
- contentView.addSubview(submitBtn)
- submitBtn.snp.makeConstraints { make in
- make.bottom.equalTo(-16)
- make.leading.equalTo(16)
- make.trailing.equalTo(-16)
- make.height.equalTo(48)
- }
-
- setUpCusStackView()
-
- // upDateCusStackViewH()
- kDelayMainShort {
- self.upDateCusStackViewH()
- }
- }
-
- override func dealThings() {
- NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
- updateVipView()
- TSAIAgeImageHintVC.userDefaultsKey = "isFirstUploadImagePTP"
- // collectionViewObserverHandle()
- //// // 监听键盘事件
- // NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
- // NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
- }
- //
- // override func viewWillAppear(_ animated: Bool) {
- // super.viewWillAppear(animated)
- // IQKeyboardManager.shared.isEnabled = false
- // }
- // override func viewWillDisappear(_ animated: Bool) {
- // super.viewWillDisappear(animated)
- //
- // IQKeyboardManager.shared.isEnabled = true
- // }
-
-
- private var collectionViewObserver: CollectionViewObserver!
-
- func collectionViewObserverHandle(){
- collectionViewObserver = CollectionViewObserver(collectionView: collectionComponent.collectionView)
-
- collectionViewObserver.onContentSizeChange = { size in
- print("collectionViewObserver 内容大小变化: \(size)")
- }
-
- collectionViewObserver.onContentInsetChange = { inset in
- print("collectionViewObserver 内边距变化: \(inset)")
- }
-
- collectionViewObserver.onContentOffsetChange = { offset in
- print("collectionViewObserver 偏移量变化: \(offset)")
- }
-
- }
-
-
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
- print("contentOffset 变化: \(scrollView.contentOffset)")
- // 实时监听偏移量变化
- }
- }
- extension TSPTPInputVC {
-
- var cusStackViewH:CGFloat{
- get {
- if cusStackView.viewH > 0{
- dePrint("collectionViewObserver cusStackView.viewH == \(cusStackView.viewH)")
- return cusStackView.viewH
- }
- return 462 //+bannerH+bannerY+promptTextViewH
- }
- }
-
- func upDateCusStackViewH(){
- let cusH = cusStackViewH
- self.collectionComponent.collectionView.contentInset = UIEdgeInsets(top: cusH, left: 0, bottom: collectionViewBtootm, right: 0)
- cusStackView.snp.remakeConstraints { make in
- make.top.equalTo(-cusH)
- make.leading.trailing.equalTo(0)
- make.height.equalTo(cusH)
- }
- self.collectionComponent.collectionView.contentOffset = CGPoint(x: 0, y: -cusH)
-
- }
-
- func presentModalHintVC(){
- let vc = TSAIAgeImageHintVC()
- vc.clickUpImageHandle = { [weak self] image,phAsset in
- guard let self = self else { return }
- handleSinglePhoto(image: image, phAsset: phAsset)
- }
- kPresentModalVC(target: self, modelVC: vc,transitionStyle: .crossDissolve)
- }
-
- func setUpCusStackView(){
-
- collectionComponent.collectionView.addSubview(cusStackView)
-
- // cusStackView.addSubviewToStack(entranceView)
- // entranceView.snp.makeConstraints { make in
- // make.height.equalTo(bannerH+bannerY)
- // make.width.equalTo(k_ScreenWidth)
- // }
- let uploadPhotoTitleView = TSTitleView.creatTitleView(title: "Upload Photo".localized, subTitle: "(Size ≤ 10MB)".localized)
- cusStackView.addSubviewToStack(uploadPhotoTitleView)
- uploadPhotoTitleView.snp.makeConstraints { make in
- make.height.equalTo(uploadPhotoTitleView.viewH)
- make.width.equalTo(k_ScreenWidth)
- }
- let hintBtn = TSUIExpandedTouchButton()
- hintBtn.setUpButton(image: UIImage(named: "ptp_hint")){ [weak self] in
- guard let self = self else { return }
- presentModalHintVC()
- }
- uploadPhotoTitleView.contentView.addSubview(hintBtn)
- hintBtn.snp.makeConstraints { make in
- make.centerY.equalToSuperview().offset(kSectionTitleViewCenterYOffset)
- make.trailing.equalTo(-16)
- make.width.height.equalTo(16)
- }
-
- cusStackView.addSubviewToStack(uploadView)
- uploadView.snp.makeConstraints { make in
- make.height.equalTo(uploadView.viewH)
- make.width.equalTo(k_ScreenWidth)
- }
-
- let selectStyleTitleView = TSTitleView.creatTitleView(title: "Select Style".localized)
- cusStackView.addSubviewToStack(selectStyleTitleView)
- selectStyleTitleView.snp.makeConstraints { make in
- make.height.equalTo(selectStyleTitleView.viewH)
- make.width.equalTo(k_ScreenWidth)
- }
-
- cusStackView.addSubviewToStack(selectStyleView)
- selectStyleView.snp.makeConstraints { make in
- make.height.equalTo(selectStyleView.viewH)
- make.width.equalTo(k_ScreenWidth)
- }
-
- // cusStackView.addSubviewToStack(promptTextView)
- // promptTextView.snp.makeConstraints { make in
- // make.height.equalTo(promptTextViewH)
- // make.width.equalTo(k_ScreenWidth)
- // }
- }
-
- override func viewDidLayoutSubviews() {
- super.viewDidLayoutSubviews()
- }
- }
- extension TSPTPInputVC: UITextViewDelegate{
- // 实现 UITextViewDelegate 协议方法,控制 return 键行为
- func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
-
- if text == "\n" {
- // 当输入为换行符(即按下 return 键)时,执行相应操作
- //sendBolck?(textView.text)
- return false
- }
- return true
- }
- }
- extension TSPTPInputVC {
-
- @objc func vipInfoChanged() {
- kExecuteOnMainThread {
- self.updateVipView()
- }
- }
- func updateVipView() {
- kExecuteOnMainThread {
- self.vipBtn.isHidden = PurchaseManager.default.isVip
-
- var showVip = kPurchaseDefault.generateVipShow(type: .picToPic)
- if showVip == false {
- showVip = self.viewModel.selectedPTPStyleModel?.isVip ?? false
- }
-
- kSetBtnVipIcon(btn: self.submitBtn, show: showVip)
- }
- }
-
- func getVipText()->String{
- return "Generate".localized
- }
-
- func updateTextFiledView () {
- // promptTextView.snp.updateConstraints { make in
- // make.height.equalTo(viewModel.selectedPTPStyleModel?.style == "No Style" ? promptTextViewH : 0 )
- // }
- }
- }
- extension TSPTPInputVC {
-
- // @objc func clickTextToPhoto() {
- // kPushVC(target: self, modelVC: TSTextGeneralPictureVC())
- // }
- //
- // @objc func clickTextToEmoji() {
- // kPushVC(target: self, modelVC: TSGenmojiVC())
- // }
-
- @objc func clickView() {
- view.endEditing(true)
- }
-
- func generateImage() {
-
- var isVip = kPurchaseDefault.freeNumAvailable(type: .picToPic) == false
- if viewModel.selectedPTPStyleModel?.isVip == true {
- isVip = true
- }
-
- //判断 vip
- if kJudgeVip(externalBool: isVip, vc: self) { [weak self] in
- guard let self = self else { return }
- }{ return }
-
- guard let selectedPTPStyleModel = viewModel.selectedPTPStyleModel else { return }
- guard let upLoadImage = viewModel.upLoadImage else { return }
- let gennerateVC = TSPTPGeneratorVC(prompt: viewModel.prompt,promptSort: selectedPTPStyleModel.imageText , imageUrl: "",upLoadImage: upLoadImage,style: selectedPTPStyleModel.style) { [weak self] model in
- guard let self = self else { return }
- if viewModel.saveModel(model:model) {
- collectionComponent.clear()
- collectionComponent.reloadView(with:viewModel.colDataArray)
- }else{
- collectionComponent.reloadData()
- }
-
- updateVipView()
- }
-
- kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
- }
- }
- extension TSPTPInputVC {
-
- @objc func keyboardWillShow(_ notification: Notification) {
- guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
- let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
- return
- }
- // dePrint("keyboardWillShow contentInset IQKeyboardManager=\(IQKeyboardManager.shared.isEnabled)")
-
- // let keyboardHeight = keyboardFrame.height
- // let contentInset = UIEdgeInsets(top:cusStackViewH, left: 0, bottom: keyboardHeight, right: 0)
- // dePrint("keyboardWillShow contentInset=\(contentInset)")
- //// UIView.animate(withDuration: animationDuration) {
- // self.collectionComponent.collectionView.contentInset = contentInset
- // self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
- //// }
-
- // kDelayMainShort {
- // self.collectionComponent.collectionView.scrollToLastItem(animated: false)
- // }
- }
- @objc func keyboardWillHide(_ notification: Notification) {
- guard let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
- return
- }
- // let contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
- // dePrint("keyboardWillHide contentInset=\(contentInset)")
- //// UIView.animate(withDuration: animationDuration) {
- // self.collectionComponent.collectionView.contentInset = contentInset
- // self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
- //// }
- }
-
-
- }
|