Visual_Novel_iOS/crush/Crush/Src/Components/UI/Sheet/ChatModePickInsufficientCoi...

304 lines
10 KiB
Swift
Raw Normal View History

2025-10-09 10:29:35 +00:00
//
// ChatModePickInsufficientCoinSheet.swift
// Crush
//
// Created by Leon on 2025/9/23.
//
import UIKit
import Combine
///
class ChatModePickInsufficientCoinSheet: EGPopBaseView {
var closeButton: EPIconTertiaryButton!
var titleLabel: UILabel!
var subTitleLabel: LineSpaceLabel!
//
var scrollView: UIScrollView!
//
var modelCardViews: [ChatModelCardView] = []
var bottomView: UIView!
var balance: CLIconLabel!
var operateButton: StyleButton! // Recharge
//
private var chatModels: [AIChatModel] = []
private var currentSelectedModelCode: String?
var cardHeight = 168.0
//
var selectionCallback: ChatModelSelectionCallback?
private var cancellables = Set<AnyCancellable>()
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(currentSelectedModelCode: String? = nil) {
self.currentSelectedModelCode = currentSelectedModelCode
super.init(direction: .bottom)
contentView.backgroundColor = .c.csbn
//
contentLength = 200 + UIWindow.safeAreaBottom
setupViews()
setupDatas()
setupEvent()
}
private func setupViews() {
closeButton = {
let v = EPIconTertiaryButton(radius: .round, iconSize: .small, iconCode: .delete)
v.addTarget(self, action: #selector(bgButtonPressed), for: .touchUpInside)
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.top.equalToSuperview().offset(20)
make.size.equalTo(v.bgImageSize())
make.trailing.equalToSuperview().offset(-16)
}
return v
}()
titleLabel = {
let v = UILabel()
v.font = .t.ttm
v.textColor = .text
v.textAlignment = .center
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.trailing.equalToSuperview().offset(-24)
make.top.equalToSuperview().offset(32)
}
return v
}()
subTitleLabel = {
let v = LineSpaceLabel()
let typo = CLSystemToken.typography(token: .tbs)
v.config(typo)
v.textColor = .c.ctpn
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(24)
make.leading.equalToSuperview().offset(CGFloat.lrs)
make.trailing.equalToSuperview().offset(-CGFloat.lrs)
}
return v
}()
scrollView = {
let v = UIScrollView()
v.showsVerticalScrollIndicator = false
v.showsHorizontalScrollIndicator = false
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview()
make.trailing.equalToSuperview()
make.top.equalTo(subTitleLabel.snp.bottom).offset(16) // 24
make.height.equalTo(cardHeight) //
}
return v
}()
bottomView = {
let v = UIView()
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.bottom.equalToSuperview().offset(-UIWindow.safeAreaBottom)
make.leading.trailing.equalToSuperview()
make.height.equalTo(80)
}
return v
}()
balance = {
let v = CLIconLabel()
v.iconSize = CGSize(width: 16, height: 16)
v.iconImageView.image = .icon16Diamond
v.contentLabel.textColor = .white
v.contentLabel.font = .t.tlm
bottomView.addSubview(v)
v.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.leading.equalToSuperview().offset(24)
}
return v
}()
operateButton = {
let v = StyleButton()
v.primary(size: .large)
v.addTarget(self, action: #selector(operateButtonTapped), for: .touchUpInside)
bottomView.addSubview(v)
v.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.trailing.equalToSuperview().offset(-24)
make.leading.greaterThanOrEqualTo(balance.snp.trailing).offset(48)
}
return v
}()
titleLabel.text = "Dialog Model"
subTitleLabel.text = "The Crush coin is insufficient and cannot continue to send messages. The charging standard of the current model"
operateButton.setTitle("Recharge", for: .normal)
}
private func setupDatas(){
// let group = DispatchGroup()
//
// group.enter()
loadChatModels {
// group.leave()
}
// group.enter()
// loadChatSetting {
// group.leave()
// }
//
// group.notify(queue: .main) {[weak self] in
// self?.setupModelCards()
// }
}
private func setupEvent(){
WalletCore.shared.$balance.sink {[weak self] balance in
if let priceLabel = self?.balance {
priceLabel.contentLabel.text = balance.displayBalance()
}
}.store(in: &cancellables)
}
private func loadChatModels(completion:(()->Void)? = nil) {
guard let models = AppDictManager.shared.chatModels, models.count > 0 else {
//
AppDictManager.shared.loadChatModelDict { [weak self] success in
if success {
self?.loadChatModels()
}
}
return
}
chatModels = models
setupModelCards()
completion?()
}
private func setupModelCards() {
//
modelCardViews.forEach { $0.removeFromSuperview() }
modelCardViews.removeAll()
//
for (index, model) in chatModels.enumerated() {
let cardView = ChatModelCardView()
cardView.configure(with: model, isSelected: model.code == currentSelectedModelCode)
cardView.tag = index
cardView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(modelCardTapped(_:))))
scrollView.addSubview(cardView)
modelCardViews.append(cardView)
cardView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.width.equalTo(scrollView.snp.width)
make.height.equalTo(cardHeight) //
if index == 0 {
make.top.equalToSuperview()
} else {
make.top.equalTo(modelCardViews[index - 1].snp.bottom).offset(12)
}
if index == chatModels.count - 1 {
make.bottom.equalToSuperview()
}
}
}
// contentLength
updateContentLength()
//
// DispatchQueue.main.async { [weak self] in
// self?.scrollToSelectedModel()
// }
}
private func updateContentLength() {
let subTitleHeight = subTitleLabel.sizeThatFits(CGSize(width: UIScreen.width - CGFloat.lrs*2, height: CGFLOAT_MAX)).height
//dlog(" \(subTitleHeight)")
// + +
let baseHeight: CGFloat = 80 + subTitleHeight + 80 + 16// titleLabel top + spacing + stayTunedLabel + bottom margin
// 200 + 12
let cardHeight: CGFloat = cardHeight
let cardSpacing: CGFloat = 12
let totalCardHeight = CGFloat(chatModels.count) * cardHeight + CGFloat(max(0, chatModels.count - 1)) * cardSpacing
// 2
let maxVisibleHeight = min(totalCardHeight, cardHeight * 2 + cardSpacing)
// scrollView
scrollView.snp.updateConstraints { make in
make.height.equalTo(maxVisibleHeight)
}
// contentLength
contentLength = baseHeight + maxVisibleHeight + UIWindow.safeAreaBottom
//
layoutIfNeeded()
}
// MARK: - Function
private func scrollToSelectedModel() {
guard let selectedCode = currentSelectedModelCode,
let selectedIndex = chatModels.firstIndex(where: { $0.code == selectedCode }),
selectedIndex < chatModels.count else { return }
// scrollViewframe
guard scrollView.frame.height > 0 else {
// frame
DispatchQueue.main.async { [weak self] in
self?.scrollToSelectedModel()
}
return
}
let offsetY = CGFloat(selectedIndex) * (cardHeight + 12) // +
scrollView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false)
}
// MARK: - Action
@objc private func modelCardTapped(_ gesture: UITapGestureRecognizer) {
guard let cardView = gesture.view as? ChatModelCardView,
let index = modelCardViews.firstIndex(of: cardView),
index < chatModels.count else { return }
let selectedModel = chatModels[index]
modelCardViews.forEach { $0.setSelected(false) }
cardView.setSelected(true)
//
selectionCallback?(selectedModel)
IMAIViewModel.shared.updateChatModel(code: selectedModel.code, completion: nil)
//
dismiss()
}
@objc private func operateButtonTapped(){
dismiss()
AppRouter.goWalletCenter()
}
}