chat setting 完善

This commit is contained in:
mh 2025-10-30 14:13:23 +08:00
parent ef162eea2c
commit 3543d9c9e8
15 changed files with 449 additions and 202 deletions

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,144 @@
//
// ChatButtleCollectionCell.swift
// Visual_Novel_iOS
//
// Created by mh on 2025/10/30.
//
import UIKit
class ChatButtleCollectionCell: UICollectionViewCell {
lazy var statusImgView: UIImageView = {
let imgView = UIImageView()
imgView.backgroundColor = .blue
return imgView
}()
lazy var stoneImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_chat_buttle_stone"))
return imgView
}()
lazy var stoneLa: UILabel = {
let lab = UILabel()
lab.font = UIFont.boldSystemFont(ofSize: 12)
lab.textColor = UIColor(hex: "#D7E7FF")
lab.text = "12"
return lab
}()
lazy var lockImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_chat_buttle_lock"))
return imgView
}()
lazy var hiImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_chat_buttle_chat"))
return imgView
}()
lazy var hiLab: UILabel = {
let lab = UILabel()
lab.text = "hi"
lab.textColor = UIColor(hex: "#333333")
lab.font = UIFont.systemFont(ofSize: 14)
return lab
}()
lazy var vipImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_chat_buttle_vip"))
return imgView
}()
lazy var nameLab: UILabel = {
let lab = UILabel()
lab.font = UIFont.boldSystemFont(ofSize: 12)
lab.text = "Default"
lab.textColor = .white
return lab
}()
lazy var getBtn: UIButton = {
let btn = UIButton()
btn.backgroundColor = UIColor(hex: "#8A48FF")
btn.setTitle("Get", for: .normal)
btn.cornerRadius = 12.5
btn.addTarget(self, action: #selector(getBtnTap), for: .touchUpInside)
return btn
}()
lazy var stoneStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [stoneImgView, stoneLa])
stackView.axis = .horizontal
stackView.spacing = 5
stackView.alignment = .center
stackView.distribution = .fill
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupData()
setupEvent()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func getBtnTap() {
}
func setupViews() {
contentView.addSubview(vipImgView)
contentView.addSubview(statusImgView)
contentView.addSubview(stoneStackView)
contentView.addSubview(lockImgView)
contentView.addSubview(hiImgView)
hiImgView.addSubview(hiLab)
contentView.addSubview(nameLab)
contentView.addSubview(getBtn)
vipImgView.snp.makeConstraints { make in
make.top.left.equalToSuperview().inset(5)
}
stoneStackView.snp.makeConstraints { make in
make.left.top.equalToSuperview().inset(5)
}
statusImgView.snp.makeConstraints { make in
make.right.equalToSuperview().inset(5)
make.centerY.equalTo(stoneStackView.snp.centerY)
make.width.height.equalTo(13)
}
hiImgView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(statusImgView.snp.bottom).offset(10)
}
hiLab.snp.makeConstraints { make in
make.centerX.centerX.equalToSuperview()
}
lockImgView.snp.makeConstraints { make in
make.right.equalToSuperview().inset(5)
make.centerY.equalTo(stoneStackView.snp.centerY)
}
nameLab.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.left.equalToSuperview().inset(5)
make.top.equalTo(hiImgView.snp.bottom).offset(15)
make.bottom.equalToSuperview().inset(10).priority(.low)
}
}
func setupData() {}
func setupEvent() {}
}

View File

@ -0,0 +1,213 @@
//
// SubItemsContainerCell.swift
// Visual_Novel_iOS
//
// Created by mh on 2025/10/30.
//
import UIKit
import SnapKit
// switch modelitem
// SubItemsRow - cell
struct SubItemsRow: RowModel {
let subItems: [ImageRow]
var cellReuseID: String { "SubItemsContainerCell" }
func cellHeight(tableWidth: CGFloat) -> CGFloat {
let maxDisplayCount = 4
let displayCount = min(subItems.count, maxDisplayCount)
return CGFloat(displayCount) * 58 // 40
}
}
// SubItemsContainerCell - cell
class SubItemsContainerCell: UITableViewCell, CellConfigurable {
private var subItems: [ImageRow] = []
private var tableViewHeightConstraint: Constraint?
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = UIColor(hex: "#F5F5FF")
tableView.showsVerticalScrollIndicator = true
tableView.isScrollEnabled = true
tableView.register(SubItemCell.self, forCellReuseIdentifier: "SubItemCell")
tableView.estimatedRowHeight = 58
tableView.rowHeight = 58
tableView.contentInset = .zero
tableView.scrollIndicatorInsets = .zero
tableView.showsVerticalScrollIndicator = false
tableView.bounces = false
tableView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] //
tableView.layer.cornerRadius = 15
return tableView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
backgroundColor = .clear
selectionStyle = .none
contentView.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(20)
make.top.bottom.equalToSuperview().inset(2.5)
tableViewHeightConstraint = make.height.equalTo(0).constraint
}
}
func configure(with row: RowModel) {
guard let subItemsRow = row as? SubItemsRow else { return }
subItems = subItemsRow.subItems
tableView.reloadData()
updateTableViewHeight()
}
private func updateTableViewHeight() {
let maxDisplayCount = 4
let displayCount = min(subItems.count, maxDisplayCount)
let height = CGFloat(displayCount) * 58
tableViewHeightConstraint?.update(offset: height)
layoutIfNeeded()
}
}
extension SubItemsContainerCell: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubItemCell", for: indexPath) as! SubItemCell
let subItem = subItems[indexPath.row]
cell.configure(with: subItem)
cell.lineView.isHidden = subItems.count - 1 == indexPath.row
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
// SubItemCell - cell
class SubItemCell: UITableViewCell {
private lazy var titleLabel: UILabel = {
let lab = UILabel()
lab.text = "Max-0618"
lab.textColor = UIColor(hex: "#333333")
lab.font = UIFont.systemFont(ofSize: 13)
return lab
}()
private lazy var iconImageView: UIImageView = {
let view = UIImageView()
view.cornerRadius = 12.5
view.backgroundColor = .darkText
return view
}()
lazy var subTitleLab: UILabel = {
let lab = UILabel()
lab.text = "Previous-generation large model"
lab.textColor = UIColor(hex: "#9494C3")
lab.font = UIFont.systemFont(ofSize: 10)
return lab
}()
lazy var tokenLab: UILabel = {
let lab = UILabel()
lab.textColor = UIColor(hex: "#0066FF")
lab.text = "0.3 points / 1K tokens (Recommended)"
lab.font = UIFont.systemFont(ofSize: 11)
return lab
}()
lazy var statusImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: ""))
imgView.backgroundColor = .blue
return imgView
}()
lazy var lineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hex: "#ECECF9")
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
backgroundColor = .clear
selectionStyle = .none
contentView.addSubview(iconImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(subTitleLab)
contentView.addSubview(tokenLab)
contentView.addSubview(statusImgView)
contentView.addSubview(lineView)
iconImageView.snp.makeConstraints { make in
make.left.top.equalToSuperview().offset(10)
make.width.height.equalTo(25)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(iconImageView.snp.right).offset(8)
make.top.equalTo(iconImageView.snp.top).offset(-2)
make.right.equalTo(statusImgView.snp.left).inset(-10)
}
subTitleLab.snp.makeConstraints { make in
make.left.equalTo(titleLabel.snp.left)
make.top.equalTo(titleLabel.snp.bottom)
make.right.equalTo(titleLabel.snp.right)
}
lineView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(10)
make.bottom.equalToSuperview()
make.height.equalTo(1)
}
tokenLab.snp.makeConstraints { make in
make.left.equalTo(titleLabel.snp.left)
make.right.equalTo(titleLabel.snp.right)
make.bottom.equalToSuperview().inset(5)
}
statusImgView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().inset(10)
make.width.height.equalTo(13)
}
}
func configure(with item: ImageRow) {
iconImageView.image = UIImage(named: item.icon)
titleLabel.text = item.title
}
}

View File

@ -35,6 +35,10 @@ class ChatSettingSwipeView: CLContainer {
// ImageRow(icon: "role_exchange_mode", title: "Sub Item 10", showAvatar: false, showArrow: false, showSwitch: false) // ImageRow(icon: "role_exchange_mode", title: "Sub Item 10", showAvatar: false, showArrow: false, showSwitch: false)
]) ])
let buttleRow = ImageRow(icon: "role_chat_buttle", title: "Chat buttle", showAvatar: false, showArrow: true, showSwitch: false, subItems: [
])
rows = [ rows = [
[modelRow, ImageRow(icon: "role_text_mode", title: "Short Text Mode", showAvatar: false, showArrow: false, showSwitch: true)], [modelRow, ImageRow(icon: "role_text_mode", title: "Short Text Mode", showAvatar: false, showArrow: false, showSwitch: true)],
[ImageRow(icon: "role_voice", title: "Voice actor", showAvatar: true, showArrow: true, showSwitch: false), ImageRow(icon: "role_talk", title: "Play dialogue only", showAvatar: false, showArrow: false, showSwitch: true)], [ImageRow(icon: "role_voice", title: "Voice actor", showAvatar: true, showArrow: true, showSwitch: false), ImageRow(icon: "role_talk", title: "Play dialogue only", showAvatar: false, showArrow: false, showSwitch: true)],
@ -272,205 +276,3 @@ extension ChatSettingSwipeView: UITableViewDelegate, UITableViewDataSource {
return CGFLOAT_MIN return CGFLOAT_MIN
} }
} }
// SubItemsRow - cell
struct SubItemsRow: RowModel {
let subItems: [ImageRow]
var cellReuseID: String { "SubItemsContainerCell" }
func cellHeight(tableWidth: CGFloat) -> CGFloat {
let maxDisplayCount = 4
let displayCount = min(subItems.count, maxDisplayCount)
return CGFloat(displayCount) * 58 // 40
}
}
// SubItemsContainerCell - cell
class SubItemsContainerCell: UITableViewCell, CellConfigurable {
private var subItems: [ImageRow] = []
private var tableViewHeightConstraint: Constraint?
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.separatorStyle = .none
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = UIColor(hex: "#F5F5FF")
tableView.showsVerticalScrollIndicator = true
tableView.isScrollEnabled = true
tableView.register(SubItemCell.self, forCellReuseIdentifier: "SubItemCell")
tableView.estimatedRowHeight = 58
tableView.rowHeight = 58
tableView.contentInset = .zero
tableView.scrollIndicatorInsets = .zero
tableView.showsVerticalScrollIndicator = false
tableView.bounces = false
tableView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner] //
tableView.layer.cornerRadius = 15
return tableView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
backgroundColor = .clear
selectionStyle = .none
contentView.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(20)
make.top.bottom.equalToSuperview().inset(2.5)
tableViewHeightConstraint = make.height.equalTo(0).constraint
}
}
func configure(with row: RowModel) {
guard let subItemsRow = row as? SubItemsRow else { return }
subItems = subItemsRow.subItems
tableView.reloadData()
updateTableViewHeight()
}
private func updateTableViewHeight() {
let maxDisplayCount = 4
let displayCount = min(subItems.count, maxDisplayCount)
let height = CGFloat(displayCount) * 58
tableViewHeightConstraint?.update(offset: height)
layoutIfNeeded()
}
}
extension SubItemsContainerCell: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SubItemCell", for: indexPath) as! SubItemCell
let subItem = subItems[indexPath.row]
cell.configure(with: subItem)
cell.lineView.isHidden = subItems.count - 1 == indexPath.row
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
// SubItemCell - cell
class SubItemCell: UITableViewCell {
private lazy var titleLabel: UILabel = {
let lab = UILabel()
lab.text = "Max-0618"
lab.textColor = UIColor(hex: "#333333")
lab.font = UIFont.systemFont(ofSize: 13)
return lab
}()
private lazy var iconImageView: UIImageView = {
let view = UIImageView()
view.cornerRadius = 12.5
view.backgroundColor = .darkText
return view
}()
lazy var subTitleLab: UILabel = {
let lab = UILabel()
lab.text = "Previous-generation large model"
lab.textColor = UIColor(hex: "#9494C3")
lab.font = UIFont.systemFont(ofSize: 10)
return lab
}()
lazy var tokenLab: UILabel = {
let lab = UILabel()
lab.textColor = UIColor(hex: "#0066FF")
lab.text = "0.3 points / 1K tokens (Recommended)"
lab.font = UIFont.systemFont(ofSize: 11)
return lab
}()
lazy var statusImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: ""))
imgView.backgroundColor = .blue
return imgView
}()
lazy var lineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hex: "#ECECF9")
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
backgroundColor = .clear
selectionStyle = .none
contentView.addSubview(iconImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(subTitleLab)
contentView.addSubview(tokenLab)
contentView.addSubview(statusImgView)
contentView.addSubview(lineView)
iconImageView.snp.makeConstraints { make in
make.left.top.equalToSuperview().offset(10)
make.width.height.equalTo(25)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(iconImageView.snp.right).offset(8)
make.top.equalTo(iconImageView.snp.top).offset(-2)
make.right.equalTo(statusImgView.snp.left).inset(-10)
}
subTitleLab.snp.makeConstraints { make in
make.left.equalTo(titleLabel.snp.left)
make.top.equalTo(titleLabel.snp.bottom)
make.right.equalTo(titleLabel.snp.right)
}
lineView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(10)
make.bottom.equalToSuperview()
make.height.equalTo(1)
}
tokenLab.snp.makeConstraints { make in
make.left.equalTo(titleLabel.snp.left)
make.right.equalTo(titleLabel.snp.right)
make.bottom.equalToSuperview().inset(5)
}
statusImgView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().inset(10)
make.width.height.equalTo(13)
}
}
func configure(with item: ImageRow) {
iconImageView.image = UIImage(named: item.icon)
titleLabel.text = item.title
}
}