角色列表数据完善 + 表情数据处理

This commit is contained in:
mh 2025-11-07 16:03:08 +08:00
parent 1f79e82668
commit beb0d3518a
15 changed files with 287 additions and 51 deletions

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,67 @@
//
// RoleTagApi.swift
// Visual_Novel_iOS
//
// Created by mh on 2025/11/7.
//
import Moya
let RoleTagProvider = APIConfig.useMock && UserAPI.useMock
? MoyaProvider<RoleTagApi>(endpointClosure: myEndpointClosure, stubClosure: { target in
let data = target.sampleData
if(data.count > 0){
return .delayed(seconds: 0.5)
}else{
return .never
}
})
: MoyaProvider<RoleTagApi>(requestClosure: myRequestClosure)
enum RoleTagApi {
static let useMock: Bool = false
case tagList(params: [String: Any])
}
extension RoleTagApi: TargetType {
var baseURL: URL {
// URL
guard let url = URL(string: APIConfig.role) else {
fatalError("Invalid baseURL: \(APIConfig.role)")
}
return url
}
var path: String {
switch self {
case .tagList:
return "/tag/list"
}
}
var method: Moya.Method {
return .post
}
var task: Task {
var mParams = [String: Any]()
switch self {
case .tagList(let params):
// mParams
mParams = params
}
return .requestParameters(parameters: mParams, encoding: JSONEncoding.default)
}
var headers: [String : String]? {
return APIConfig.apiHeaders()
}
var sampleData: Data {
switch self {
case .tagList:
return Data()
}
}
}

View File

@ -0,0 +1,49 @@
//
// ChatRoleTagViewModel.swift
// Visual_Novel_iOS
//
// Created by mh on 2025/11/7.
//
import Foundation
struct RoleTagRequest: Codable {
var limit = 20
var name: String = ""
}
struct RoleTagModel: Codable {
var total: Int = 0
var rows: [RoleTagItem] = []
}
struct RoleTagItem: Codable {
var id: Int = 0
var name: String = ""
}
class ChatRoleTagViewModel {
func loadRoleTags(name: String, limit: Int = 20, completion: ((_ datas: RoleTagModel?) -> Void)?) {
var req = RoleTagRequest()
req.limit = limit
req.name = name
let params = req.toNonNilDictionary()
RoleTagProvider.request(.tagList(params: params), modelType: RoleTagModel.self) { result in
switch result {
case .success(let model):
// RoleListModel
if let model = model {
completion?(model)
} else {
completion?(nil)
}
case .failure(let failure):
dlog("⛔️ 加载角色标签失败: \(failure)")
completion?(nil)
}
}
}
}

View File

@ -8,6 +8,8 @@
import Foundation
import CodableWrappers
//
// request
struct RoleListRequest: Codable {
var index = 1
@ -34,7 +36,7 @@ struct RoleItem: Codable {
class ChatRoleViewModel {
func loadRoles(index: Int, limit: Int = 20, name: String = "", sourceId: Int = -1, tagId: Int? = nil, completion: ((_ datas: [RoleListModel]?) -> Void)?) {
func loadRoles(index: Int, limit: Int = 20, name: String = "", sourceId: Int = -1, tagId: Int? = nil, completion: ((_ datas: RoleListModel?) -> Void)?) {
var req = RoleListRequest()
req.index = index
req.limit = limit
@ -51,7 +53,7 @@ class ChatRoleViewModel {
case .success(let model):
// RoleListModel
if let model = model {
completion?([model])
completion?(model)
} else {
completion?(nil)
}

View File

@ -94,10 +94,10 @@ class HomePageRootController: CLTabRootController<HomePageRootView> {
}
private func setupDatas() {
setupOrResetFilterModel()
// viewModel.loadCards()
loadFirstCards()
// setupOrResetFilterModel()
//
// // viewModel.loadCards()
// loadFirstCards()
}
private func setupOrResetFilterModel(loadNewData: Bool = false){

View File

@ -9,5 +9,14 @@ import Foundation
struct CLRoleTagsModel: Codable {
var name: String = ""
var id: Int = 0
var isSelected: Bool = false
}
extension CLRoleTagsModel {
init(_ item: RoleTagItem) {
self.id = item.id
self.name = item.name
self.isSelected = false
}
}

View File

@ -14,7 +14,8 @@ class RolesRootPageController: CLTabRootController<RolesRootPageView> {
private var cancellables = Set<AnyCancellable>()
var page: Int = 1
var viewModel: ChatRoleViewModel = ChatRoleViewModel()
var tagViewModel: ChatRoleTagViewModel = ChatRoleTagViewModel()
override func viewDidLoad() {
super.viewDidLoad()
@ -29,11 +30,13 @@ class RolesRootPageController: CLTabRootController<RolesRootPageView> {
setupViews()
setupEvent()
loadRoles(page: 1)
loadTags()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadData()
}
private func setupViews() {
@ -51,15 +54,15 @@ class RolesRootPageController: CLTabRootController<RolesRootPageView> {
.store(in: &cancellables)
}
func loadData() {
// if page == 1{
//// loadedAiIds.removeAll()
// }
viewModel.loadRoles(index: page) { datas in
print(datas)
print("11111")
func loadRoles(page: Int) {
viewModel.loadRoles(index: page) { [weak self] datas in
self?.container.config(datas?.rows, isFirstPage: page == 1)
}
}
func loadTags() {
tagViewModel.loadRoleTags(name: "") { datas in
self.container.configureTags(datas?.rows)
}
}

View File

@ -6,6 +6,7 @@
//
import UIKit
import SDWebImage
class CLRoleCollectionCell: UICollectionViewCell {
@ -17,12 +18,38 @@ class CLRoleCollectionCell: UICollectionViewCell {
return imgView
}()
lazy var bookImgView: UIImageView = {
let imgView = UIImageView()
imgView.backgroundColor = .blue
imgView.cornerRadius = 7
return imgView
}()
lazy var fromImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_from"))
imgView.contentMode = .scaleAspectFill
return imgView
}()
lazy var playImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_type_play"))
imgView.isHidden = true
return imgView
}()
lazy var readImgView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "role_type_read"))
return imgView
}()
lazy var typeStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [playImgView, readImgView])
stackView.spacing = 0
stackView.distribution = .fill
stackView.alignment = .fill
return stackView
}()
lazy var coverImgView: UIImageView = {
let imgView = UIImageView()
imgView.contentMode = .scaleAspectFill
@ -105,8 +132,11 @@ class CLRoleCollectionCell: UICollectionViewCell {
}
// MARK: data
func setupData(desc: String) {
descLab.text = desc
func setupData(item: RoleItem) {
descLab.text = item.name
nameLab.text = item.name
coverImgView.sd_setImage(with: URL(string: item.coverImage), placeholderImage: nil)
// coverImgView.
}
// MARK: subviews
@ -117,7 +147,9 @@ class CLRoleCollectionCell: UICollectionViewCell {
contentView.addSubview(bottomShadowImgView)
contentView.addSubview(bookBgImgView)
contentView.addSubview(fromImgView)
bookBgImgView.addSubview(bookImgView)
// contentView.addSubview(fromImgView)
bookImgView.addSubview(typeStackView)
contentView.addSubview(starImgView)
contentView.addSubview(sourceLab)
@ -148,9 +180,19 @@ class CLRoleCollectionCell: UICollectionViewCell {
bookBgImgView.snp.makeConstraints { make in
make.top.left.equalToSuperview()
}
//
// fromImgView.snp.makeConstraints { make in
// make.top.left.equalToSuperview()
// }
fromImgView.snp.makeConstraints { make in
make.top.left.equalToSuperview()
bookImgView.snp.makeConstraints { make in
make.left.top.equalToSuperview().inset(3)
make.right.equalToSuperview().inset(4)
make.bottom.equalToSuperview().inset(10)
}
typeStackView.snp.makeConstraints { make in
make.bottom.right.equalToSuperview().inset(0)
}
sourceLab.snp.makeConstraints { make in

View File

@ -11,16 +11,20 @@ class CLRoleTagsView: UIView {
// let tags = ["#", "#", "#", "#", "#this is good", "#", "#", "#a", "#a"]
var tagModels: [CLRoleTagsModel] = [
CLRoleTagsModel(name: "#浪漫浪漫浪漫浪漫浪漫浪漫浪漫浪漫浪漫漫浪漫浪漫浪漫漫浪漫浪漫浪漫漫浪漫浪漫浪漫", isSelected: false),
CLRoleTagsModel(name: "#温柔", isSelected: false),
CLRoleTagsModel(name: "#多愁善感", isSelected: false),
CLRoleTagsModel(name: "#this is good", isSelected: false),
CLRoleTagsModel(name: "#沙瓦迪", isSelected: false),
CLRoleTagsModel(name: "#科技哈", isSelected: false),
CLRoleTagsModel(name: "#等好a", isSelected: false),
CLRoleTagsModel(name: "#a", isSelected: false),
CLRoleTagsModel(name: "#浪漫", isSelected: false),
]
// CLRoleTagsModel(name: "#", isSelected: false),
// CLRoleTagsModel(name: "#", isSelected: false),
// CLRoleTagsModel(name: "#", isSelected: false),
// CLRoleTagsModel(name: "#this is good", isSelected: false),
// CLRoleTagsModel(name: "#", isSelected: false),
// CLRoleTagsModel(name: "#", isSelected: false),
// CLRoleTagsModel(name: "#a", isSelected: false),
// CLRoleTagsModel(name: "#a", isSelected: false),
// CLRoleTagsModel(name: "#", isSelected: false),
] {
didSet {
self.collectionView.reloadData()
}
}
lazy var collectionView: AutoHeightCollectionView = {
let layout = TagFlowLayout()

View File

@ -15,24 +15,23 @@ class RolesRootPageView: CLContainer {
let itemWidth: CGFloat = (UIScreen.width - 30.0) / 2.0
var jumpPublisher: AnyPublisher<JumpTarget, Never> { topView.jumpPublisher }
// private lazy var pagingView = JXPagingListRefreshView(delegate: self)
// lazy var headerView:
let data: [String] = [
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy, Lin Feng had his cultivation shattered and was cast",
"Once a prodigy, Lin Feng had his cultivation",
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy",
"Once a prodigy",
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy, Lin Feng had his cultivation shattered and was cast Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy, Lin Feng had his cultivation shattered and was cast",
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy",
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy",
"Once a prodigy",
"Once a prodigy, Lin Feng had his cultivation shattered and was cast out Once a prodigy, Lin Feng had his cultivation shattered and was cast",
"Once a prodigy"
]
// private lazy var pagingView = JXPagingListRefreshView(delegate: self)
// lazy var headerView:
var data: [RoleItem] = []
let remind: [String] = [
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
"[The Lsat Oracle of Kael]",
@ -83,7 +82,7 @@ class RolesRootPageView: CLContainer {
private func setupViews() {
addSubview(self.topView)
// addSubview(tagsChooseView)
// addSubview(tagsChooseView)
addSubview(tagsView)
addSubview(collectionView)
@ -106,6 +105,23 @@ class RolesRootPageView: CLContainer {
private func setupDatas() {
}
func config(_ data: [RoleItem]?, isFirstPage: Bool){
if isFirstPage {
self.data = data ?? []
} else {
self.data.append(contentsOf: data ?? [])
}
self.collectionView.reloadData()
}
func configureTags(_ data: [RoleTagItem]?) {
guard let tags = data else {
self.tagsView.tagModels = []
return
}
self.tagsView.tagModels = tags.map(CLRoleTagsModel.init)
}
}
extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSource, WaterfallLayoutDelegate {
@ -116,7 +132,7 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: CLRoleCollectionCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CLRoleCollectionCell", for: indexPath) as! CLRoleCollectionCell
cell.setupData(desc: data[indexPath.item])
cell.setupData(item: data[indexPath.item])
return cell
}
@ -139,7 +155,7 @@ extension RolesRootPageView: UICollectionViewDelegate, UICollectionViewDataSourc
let maxHeight = lineHeight * CGFloat(maxLines)
// maxHeight
let textSize = model.boundingRect(
let textSize = model.name.boundingRect(
with: CGSize(width: itemWidth - 20, height: maxHeight), //
options: [.usesLineFragmentOrigin, .usesFontLeading],
attributes: [.font: font],