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

523 lines
17 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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)
}
}
}
}