|
@@ -45,31 +45,105 @@ class TSChatViewController: MessagesViewController, MessagesDataSource {
|
|
|
// MARK: Private
|
|
|
lazy var textMessageSizeCalculator = TSTextLayoutSizeCalculator(layout: self.messagesCollectionView.messagesCollectionViewFlowLayout)
|
|
|
|
|
|
-
|
|
|
lazy var inputBarVC: TSChatInputBarVC = {
|
|
|
let inputBarVC = TSChatInputBarVC()
|
|
|
inputBarVC.sendComplete = { [weak self] components in
|
|
|
guard let self = self else { return }
|
|
|
- sendMessages(components)
|
|
|
- messagesCollectionView.scrollToLastItem(animated: true)
|
|
|
+ inputSendMsg(components)
|
|
|
}
|
|
|
return inputBarVC
|
|
|
}()
|
|
|
|
|
|
|
|
|
-
|
|
|
- lazy var text: UILabel = {
|
|
|
- let textLabel = UILabel.createLabel(text: "Remaining 3 free times")
|
|
|
+ let inputBarBgView:UIView = {
|
|
|
+ let inputBarBgView = UIView()
|
|
|
+ inputBarBgView.addShadow(shadowColor: "#111111".uiColor.cgColor, shadowOffset: CGSize(width: 0, height: -10), shadowRadius: 10, shadowOpacity: 1.0)
|
|
|
+ return inputBarBgView
|
|
|
+ }()
|
|
|
+ let inputBarTopView:UIView = UIView()
|
|
|
+
|
|
|
+ //免费次数
|
|
|
+ lazy var freeText: UILabel = {
|
|
|
+ let textLabel = UILabel.createLabel(
|
|
|
+ text: "Remaining \(kPurchaseDefault.freeNum(type: .aichat)) free times",
|
|
|
+ font: .font(size: 12),
|
|
|
+ textColor: "#E83E3E".uiColor,
|
|
|
+ textAlignment: .center,
|
|
|
+ numberOfLines: 0
|
|
|
+ )
|
|
|
+ textLabel.isHidden = false
|
|
|
return textLabel
|
|
|
}()
|
|
|
|
|
|
|
|
|
+ lazy var upgradeVipBg: UIView = {
|
|
|
+ let upgradeVipBg = UIView()
|
|
|
+
|
|
|
+ let imageView = UIImageView.createImageView(imageName: "vip_upgrade_bg",contentMode: .scaleToFill)
|
|
|
+ upgradeVipBg.addSubview(imageView)
|
|
|
+ imageView.snp.makeConstraints { make in
|
|
|
+ make.edges.equalToSuperview()
|
|
|
+ }
|
|
|
+
|
|
|
+ let label = UILabel.createLabel(
|
|
|
+ text:"Free usage limit reached. Upgrade for unlimited chats.".localized,
|
|
|
+ font: .font(size: 14,weight: .bold),
|
|
|
+ textColor: "#111111".uiColor,
|
|
|
+ numberOfLines: 0
|
|
|
+ )
|
|
|
+ upgradeVipBg.addSubview(label)
|
|
|
+ label.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(16)
|
|
|
+ make.top.equalTo(8)
|
|
|
+ make.bottom.equalTo(-8)
|
|
|
+ make.trailing.equalTo(-95)
|
|
|
+ }
|
|
|
+
|
|
|
+ let upgradeBtn = UIButton.createButton(
|
|
|
+ title: "Upgrade".localized,
|
|
|
+ backgroundColor: "#111111".uiColor,
|
|
|
+ font:.font(size: 12,weight: .medium),
|
|
|
+ titleColor:.white,
|
|
|
+ corner: 14) { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ TSPurchaseVC.show(target: self) { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ updateVipView()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ upgradeVipBg.addSubview(upgradeBtn)
|
|
|
+ upgradeBtn.snp.makeConstraints { make in
|
|
|
+ make.trailing.equalTo(-12)
|
|
|
+ make.centerY.equalToSuperview()
|
|
|
+ make.width.equalTo(70)
|
|
|
+ make.height.equalTo(28)
|
|
|
+ }
|
|
|
+ return upgradeVipBg
|
|
|
+ }()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ lazy var scrollToBottomButton: UIButton = {
|
|
|
+ let backBottomBtn = UIButton.createButton(image: UIImage(named: "down_arrow_line")) { [weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ messagesCollectionView.scrollToLastItem(animated: false)
|
|
|
+ }
|
|
|
+ backBottomBtn.isHidden = true
|
|
|
+ backBottomBtn.backgroundColor = .popupColor
|
|
|
+ backBottomBtn.cornerRadius = 16.0
|
|
|
+ return backBottomBtn
|
|
|
+ }()
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
override func viewDidLoad() {
|
|
|
super.viewDidLoad()
|
|
|
navigationItem.title = "MessageKit"
|
|
|
|
|
|
configureMessageCollectionView()
|
|
|
configureMessageInputBar()
|
|
|
+ configureOtherUI()
|
|
|
loadFirstMessages()
|
|
|
|
|
|
|
|
@@ -127,37 +201,69 @@ class TSChatViewController: MessagesViewController, MessagesDataSource {
|
|
|
}
|
|
|
|
|
|
func configureMessageInputBar() {
|
|
|
- let clearView = UIView()
|
|
|
- clearView.backgroundColor = .clear
|
|
|
-
|
|
|
+
|
|
|
+ inputBarBgView.addSubview(inputBarTopView)
|
|
|
+ inputBarTopView.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(0)
|
|
|
+ make.trailing.equalTo(0)
|
|
|
+ make.top.equalTo(0)
|
|
|
+ }
|
|
|
+
|
|
|
if viewModel.uiStyle == .chat {
|
|
|
- clearView.addSubview(inputBarVC.view)
|
|
|
+ inputBarBgView.addSubview(inputBarVC.view)
|
|
|
inputBarVC.view.snp.makeConstraints { make in
|
|
|
make.leading.equalTo(0)
|
|
|
make.trailing.equalTo(0)
|
|
|
- make.top.equalTo(0)
|
|
|
+ make.top.equalTo(inputBarTopView.snp.bottom)
|
|
|
make.bottom.equalTo(0)
|
|
|
}
|
|
|
}
|
|
|
- inputBarType = .custom(clearView)
|
|
|
-
|
|
|
-
|
|
|
- let redView = UIView()
|
|
|
- redView.backgroundColor = .red
|
|
|
- view.addSubview(redView)
|
|
|
- redView.snp.makeConstraints { make in
|
|
|
- make.leading.equalTo(20)
|
|
|
- make.trailing.equalTo(-20)
|
|
|
- make.height.equalTo(30)
|
|
|
-// make.bottom.equalTo(-10)
|
|
|
- make.bottom.equalTo(inputContainerView.snp.top).offset(-10)
|
|
|
-
|
|
|
+ inputBarType = .custom(inputBarBgView)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ func configureOtherUI() {
|
|
|
+ view.addSubview(scrollToBottomButton)
|
|
|
+ scrollToBottomButton.snp.makeConstraints { make in
|
|
|
+ make.centerX.equalToSuperview()
|
|
|
+ make.bottom.equalTo(inputContainerView.snp.top).offset(-14)
|
|
|
+ make.width.height.equalTo(32)
|
|
|
}
|
|
|
+ self.scrollViewDidScroll(self.messagesCollectionView)
|
|
|
|
|
|
+ updateVipView()
|
|
|
+ }
|
|
|
+
|
|
|
+ func updateVipView() {
|
|
|
+ inputBarTopView.subviews.forEach { $0.removeFromSuperview()}
|
|
|
|
|
|
-
|
|
|
+ if viewModel.uiStyle == .chat ,
|
|
|
+ kPurchaseDefault.isVip == false
|
|
|
+ {
|
|
|
+ let freeNum = kPurchaseDefault.freeNum(type: .aichat)
|
|
|
+ if freeNum > 0 {
|
|
|
+ freeText.text = "Remaining \(freeNum) free times"
|
|
|
+ inputBarTopView.addSubview(freeText)
|
|
|
+ freeText.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(20)
|
|
|
+ make.trailing.equalTo(-20)
|
|
|
+ make.bottom.equalTo(-8)
|
|
|
+ make.top.equalTo(8)
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ inputBarTopView.addSubview(upgradeVipBg)
|
|
|
+ upgradeVipBg.snp.makeConstraints { make in
|
|
|
+ make.leading.equalTo(16)
|
|
|
+ make.trailing.equalTo(-16)
|
|
|
+ make.bottom.equalTo(-2)
|
|
|
+ make.top.equalTo(14)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
// MARK: - Helpers
|
|
|
var lastIndexPath:IndexPath{
|
|
|
if messageList.count == 0 {
|
|
@@ -310,9 +416,6 @@ extension TSChatViewController: InputBarAccessoryViewDelegate {
|
|
|
//保存这条消息到本地数据库
|
|
|
//发送消息后,进行AI 对话生成
|
|
|
generativeAIChat(message: message)
|
|
|
- } else if let img = component as? UIImage {
|
|
|
- // let message = TSChatMessage(image: img, user: user, messageId: UUID().uuidString, date: Date())
|
|
|
- // insertMessage(message)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -347,6 +450,9 @@ extension TSChatViewController: InputBarAccessoryViewDelegate {
|
|
|
if let netData = data {
|
|
|
message.sendState = .success("netData")
|
|
|
//保存这条消息到本地数据库
|
|
|
+ //消耗一次 AI 次数
|
|
|
+ kPurchaseDefault.useOnceForFree(type: .aichat)
|
|
|
+
|
|
|
}else {
|
|
|
message.kind = .attributedText(kMDAttributedString(text: kAIErrorString))
|
|
|
message.sendState = .failed(kAIErrorString)
|
|
@@ -369,12 +475,50 @@ extension TSChatViewController: InputBarAccessoryViewDelegate {
|
|
|
}else{
|
|
|
self.messagesCollectionView.reloadData()
|
|
|
}
|
|
|
+
|
|
|
+ //更新 Vip
|
|
|
+ if kPurchaseDefault.isVip == false{
|
|
|
+ self.updateVipView()
|
|
|
+ }
|
|
|
+
|
|
|
+ self.messagesCollectionView.scrollToLastItem(animated: false)
|
|
|
|
|
|
-// if self.isLastSectionVisible() == true {
|
|
|
- self.messagesCollectionView.scrollToLastItem(animated: false)
|
|
|
-// }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
+extension TSChatViewController{
|
|
|
+
|
|
|
+ func inputSendMsg(_ data: [Any]) {
|
|
|
+
|
|
|
+ //判断 vip
|
|
|
+ if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .aichat) == false, vc: self, closePageBlock: {[weak self] in
|
|
|
+ guard let self = self else { return }
|
|
|
+ }){ return }
|
|
|
+
|
|
|
+ sendMessages(data)
|
|
|
+ messagesCollectionView.scrollToLastItem(animated: true)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+extension TSChatViewController{
|
|
|
+
|
|
|
+ // UICollectionViewDelegate 方法
|
|
|
+ override func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
|
+ let offsetY = scrollView.contentOffset.y
|
|
|
+ let contentHeight = scrollView.contentSize.height
|
|
|
+ let frameHeight = scrollView.frame.size.height
|
|
|
+
|
|
|
+ // 判断是否需要显示滚动到底部的按钮
|
|
|
+ if offsetY > contentHeight - frameHeight - 400 {
|
|
|
+ scrollToBottomButton.isHidden = true
|
|
|
+ } else {
|
|
|
+ scrollToBottomButton.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|