角色列表数据完善 + 表情数据处理
This commit is contained in:
parent
1f79e82668
commit
beb0d3518a
|
|
@ -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
|
||||
}
|
||||
}
|
||||
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_play.imageset/role_type_play@2x.png
vendored
Normal file
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_play.imageset/role_type_play@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 951 B |
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_play.imageset/role_type_play@3x.png
vendored
Normal file
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_play.imageset/role_type_play@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -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
|
||||
}
|
||||
}
|
||||
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_read.imageset/role_type_read@2x.png
vendored
Normal file
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_read.imageset/role_type_read@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_read.imageset/role_type_read@3x.png
vendored
Normal file
BIN
Visual_Novel_iOS/Assets.xcassets/Role/role_type_read.imageset/role_type_read@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
Loading…
Reference in New Issue