Visual_Novel_iOS/crush/Crush/Src/Modules/Role/Home/RoleHomeAlbumController.swift

523 lines
17 KiB
Swift
Raw Normal View History

2025-10-09 10:29:35 +00:00
//
// RoleHomeAlbumController.swift
// Crush
//
// Created by Leon on 2025/7/24.
//
import JXPagingView
import SnapKit
import UIKit
import Combine
class RoleHomeAlbumController: CLBaseGridController {
var aiId: Int?
var userId: Int?
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupViews()
setupDats()
setupEvents()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
layout.invalidateLayout()
}
private func setupViews() {
collectionView.snp.remakeConstraints { make in
make.edges.equalToSuperview()
}
navigationView.isHidden = true
collectionView.register(RoleHomeAlbumGridCell.self, forCellWithReuseIdentifier: "RoleHomeAlbumGridCell")
let itemW = floor((UIScreen.width - 24 * 2 - 16) * 0.5) as CGFloat
let itemH = itemW
// layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: itemW, height: itemH)
layout.minimumLineSpacing = 16
layout.minimumInteritemSpacing = 16
layout.sectionInset = UIEdgeInsets(top: 12, left: 24, bottom: 12 + UIWindow.safeAreaBottom, right: 24)
layout.invalidateLayout()
addRefreshHeader()
addRefreshFooter()
collectionView.mj_header?.beginRefreshing()
}
private func setupDats() {
}
override func loadData() {
guard let id = aiId else {return }
let pageData = RequestPageData()
pageData.pn = page
let pageParams = pageData.toNonNilDictionary()
var params = [String: Any]()
params.updateValue(id, forKey: "aiId")
params.updateValue(pageParams, forKey: "page")
AIRoleProvider.request(.aiRoleAlbumList(params: params), modelType: ResponseContentPageData<AlbumPhotoItem>.self) {[weak self] result in
self?.collectionView.mj_header?.endRefreshing()
self?.collectionView.mj_footer?.endRefreshing()
switch result {
case .success(let success):
if let albums = success?.datas{
if(pageData.pn == 1){
self?.datas = albums
self?.collectionView.mj_footer?.resetNoMoreData()
self?.view.setupEmpty(empty: albums.count <= 0, msg: "暂无图片")
}else{
self?.datas.append(contentsOf: albums)
if albums.count <= 0{
self?.collectionView.mj_footer?.endRefreshingWithNoMoreData()
}
}
self?.collectionView.reloadData()
}
case .failure:
break
}
}
}
private func setupEvents() {
NotificationCenter.default.addObserver(self, selector: #selector(notiAlbumsInfoChanged), name: AppNotificationName.aiRoleAlbumPhotoInfoChanged.notificationName, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(notiAlbumsAddOrDeleted), name: AppNotificationName.aiRoleAlbumAddOrDelete.notificationName, object: nil)
PhotosViewModel.shared.$album.sink {[weak self] photo in
guard let self = self else{return}
guard let album = photo , let albumId = photo?.albumId else {return}
for per in self.datas{
guard let perAlbum = per as? AlbumPhotoItem else {return}
if albumId == perAlbum.albumId{
perAlbum.updateFrom(album)
self.collectionView.reloadData()
break
}
}
}.store(in: &cancellables)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return datas.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RoleHomeAlbumGridCell", for: indexPath) as! RoleHomeAlbumGridCell
let data = datas[indexPath.item]
cell.isSelf = UserCore.shared.isSelfByUid(uid: userId)
cell.config(data: data as? AlbumPhotoItem)
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let album = datas[indexPath.item] as? AlbumPhotoItem else {return}
// guard let uid = userId else{return}
// if album.lockStatus == .locked && !UserCore.shared.isSelf(id: userId){
// return
// }
var photoModels = [PhotoBrowserModel]()
for (index, per) in datas.enumerated() {
guard let perAlbum = per as? AlbumPhotoItem else{
return
}
let model = PhotoBrowserModel()
model.aiAlbum = perAlbum
model.aiId = aiId
model.imageUrl = perAlbum.getImgUrl()
if index == indexPath.item{
if let cell = collectionView.cellForItem(at: indexPath) as? RoleHomeAlbumGridCell{
model.image = cell.imageView.image
model.sourceRect = cell.screenRect ?? .zero
}
}
model.deleteTapBlock = { [weak self] model, completeBlock in
// req api to delete photo
// #warning("test")
// Hud.showIndicator()
// DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// Hud.hideInidcator()
// completeBlock(true)
// }
Hud.showIndicator()
AIRoleProvider.request(.aiRoleAlbumDel(userId: self?.userId, albumId: model.aiAlbum.albumId), modelType: EmptyModel.self) { result in
Hud.hideIndicator()
switch result {
case .success:
completeBlock(true)
NotificationCenter.post(name: .aiRoleAlbumAddOrDelete)
case .failure:
completeBlock(false)
}
}
}
photoModels.append(model)
}
if UserCore.shared.isSelf(id: userId){
ImageBrowser.show(models: photoModels, index: indexPath.item, type: .roleMine)
}else{
ImageBrowser.show(models: photoModels, index: indexPath.item, type: .roleOthersInAlbum)
}
}
@objc private func notiAlbumsInfoChanged(){
collectionView.mj_header?.beginRefreshing()
}
@objc private func notiAlbumsAddOrDeleted(){
collectionView.mj_header?.beginRefreshing()
}
}
extension RoleHomeAlbumController: JXPagingViewListViewDelegate {
func listView() -> UIView {
return view
}
func listScrollView() -> UIScrollView {
return collectionView
}
func listViewDidScrollCallback(callback: @escaping (UIScrollView) -> Void) {
listViewDidScrollCallback = callback
}
}
class RoleHomeAlbumGridCell: UICollectionViewCell {
var imageView: AutoRatioImageView!
/// 🚩
var normalContainer: UIView!
/// flag
var flagOfDefault: EPTagLabel!
///
var lockFlag: EPIconFlagView!
var unlockedFlag: EPIconPrimaryButton! // 🔓 +
///
var likeView: HeartLikeCountView!
/// 🚩LockContainer
var lockContainer: UIView!
var unlockCoinLabel: UILabel!
// Flag
public var usedInMeetCard : Bool = false
// @Required
public var data: AlbumPhotoItem?
// @Required
public var isSelf: Bool = false
//
private var isRequesting = false
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupData()
setupEvent()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//
func config(data:AlbumPhotoItem?){
self.data = data;
guard let photo = data else {return}
//imageView.loadImage(data?.getImgUrl())
imageView.setImage(with: data?.getImgUrl().urlValue)
likeView.isLike = photo.likedStatus == .liked
let likedCount = photo.likedCount ?? 0
let likeCountDisplay = String.displayNumber(NSNumber(value: likedCount), scale: 1)
likeView.countLabel.text = likeCountDisplay// String.displayInteger(photo.likedCount ?? 0)
if isSelf{
lockContainer.isHidden = true
normalContainer.isHidden = false
unlockedFlag.isHidden = true
lockFlag.isHidden = true
if let lockStatus = photo.lockStatus{
lockFlag.isHidden = lockStatus != .unlock
}
flagOfDefault.isHidden = !photo.isDefault.boolValue
}else{
flagOfDefault.isHidden = true
lockFlag.isHidden = true
unlockedFlag.isHidden = true
if let lockStatus = photo.lockStatus{
if lockStatus == .unlock{
//
lockContainer.isHidden = true
normalContainer.isHidden = false
unlockedFlag.isHidden = false
flagOfDefault.isHidden = !photo.isDefault.boolValue
}else if lockStatus == .locked{
//
lockContainer.isHidden = false
normalContainer.isHidden = true
let coin = Coin(cents: (data?.unlockPrice ?? 0))
unlockCoinLabel.text = "\(coin.formatted) unlock"
}
}else{
// Open
lockContainer.isHidden = true
normalContainer.isHidden = false
flagOfDefault.isHidden = !photo.isDefault.boolValue
}
if usedInMeetCard{
flagOfDefault.isHidden = true
}
}
}
private func setupViews() {
contentView.backgroundColor = .c.csnn
contentView.layer.cornerRadius = 16
contentView.layer.masksToBounds = true
imageView = {
let v = AutoRatioImageView()
v.layer.cornerRadius = 16
v.layer.masksToBounds = true
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
}
return v
}()
normalContainer = {
let v = UIView()
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
flagOfDefault = {
let v = EPTagLabel(style: .blackOnColor)
normalContainer.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(8)
make.top.equalToSuperview().offset(8)
}
return v
}()
lockFlag = {
let v = EPIconFlagView(frame: .zero)
v.setupRightTopLockStyle()
normalContainer.addSubview(v)
v.snp.makeConstraints { make in
make.top.equalToSuperview().offset(8)
make.trailing.equalToSuperview().offset(-8)
}
v.isHidden = true
return v
}()
unlockedFlag = {
let v = EPIconPrimaryButton(radius: .rectangle, iconSize: .xs, iconCode: .iconPublic)
v.layer.cornerRadius = 4
normalContainer.addSubview(v)
v.snp.makeConstraints { make in
make.top.equalToSuperview().offset(8)
make.trailing.equalToSuperview().offset(-8)
}
v.isHidden = true
return v
}()
likeView = {
let v = HeartLikeCountView()
normalContainer.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(8)
make.bottom.equalToSuperview().offset(-8)
}
return v
}()
setupLockStateViews()
flagOfDefault.text = "Default"
likeView.countLabel.text = "0"
// #warning("test")
// testData()
}
private func setupLockStateViews() {
lockContainer = {
let v = UIView()
contentView.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
let stackV = {
let v = UIStackView()
v.axis = .vertical
v.alignment = .center
v.spacing = 16
lockContainer.addSubview(v)
v.snp.makeConstraints { make in
make.center.equalToSuperview()
make.left.greaterThanOrEqualToSuperview()
make.right.lessThanOrEqualToSuperview()
}
return v
}()
let lockIcon = {
let v = UIImageView()
v.image = MWIconFont.image(fromIcon: .iconPrivate, size: CGSize(width: 24, height: 24), color: .white)
stackV.addArrangedSubview(v)
return v
}()
lockIcon.isHidden = false
let stackH = {
let v = UIStackView()
v.spacing = 4
v.alignment = .center
stackV.addArrangedSubview(v)
return v
}()
let coinIv = {
let v = UIImageView()
v.image = UIImage(named: "icon_16_diamond")
stackH.addArrangedSubview(v)
return v
}()
coinIv.isHidden = false
unlockCoinLabel = {
let v = UILabel()
v.textColor = .text
v.font = .t.tlm
stackH.addArrangedSubview(v)
return v
}()
}
private func setupData(){
}
private func setupEvent(){
likeView.likeButton.addTarget(self, action: #selector(tapLikeHeart), for: .touchUpInside)
}
private func testData() {
imageView.image = UIImage(named: "egpic")
unlockCoinLabel.text = "123 unlock"
lockContainer.backgroundColor = .random
normalContainer.isHidden = true
lockContainer.isHidden = false
}
@objc private func tapLikeHeart() {
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{return}
//
guard !isRequesting else { return }
guard let album = self.data else { return }
let albumId = album.albumId
isRequesting = true
//
likeView.likeButton.isEnabled = false
if album.likedStatus == .liked {
//
album.likedStatus = .cancel
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
config(data: album)
AIRoleProvider.request(.aiRolePhotoLikeOrNo(albumId: albumId, likedStatus: .cancel), modelType: EmptyModel.self) { [weak self] result in
self?.handleLikeRequestResult(result: result, albumId: albumId, isLike: false)
}
} else {
//
likeView.playLotteLike { [weak self] completed in
guard let album = self?.data else { return }
album.likedStatus = .liked
album.likedCount = (album.likedCount ?? 0) + 1
self?.config(data: album)
}
AIRoleProvider.request(.aiRolePhotoLikeOrNo(albumId: albumId, likedStatus: .liked), modelType: EmptyModel.self) { [weak self] result in
self?.handleLikeRequestResult(result: result, albumId: albumId, isLike: true)
}
}
}
//
private func handleLikeRequestResult(result: Result<EmptyModel?, ResponseError>, albumId: Int, isLike: Bool) {
isRequesting = false
likeView.likeButton.isEnabled = true
switch result {
case .success:
//
break
case .failure:
//
if let currentId = self.data?.albumId, currentId == albumId {
guard let album = self.data else { return }
if isLike {
//
album.likedStatus = .cancel
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
} else {
//
album.likedStatus = .liked
album.likedCount = (album.likedCount ?? 0) + 1
}
config(data: album)
}
}
}
}