Visual_Novel_iOS/crush/Crush/Src/Components/Photo/PhotoBrowser/PhotoBrowserControllerExtRo...

438 lines
17 KiB
Swift
Raw Normal View History

2025-10-09 10:29:35 +00:00
//
// PhotoBrowserControllerExtRole.swift
// Crush
//
// Created by Leon on 2025/7/27.
//
extension PhotoBrowserController {
// MARK: - 🚩My Role
func createOperateViewOfRoleMine() {
bottomGradientContainer?.isHidden = false
rolePhotoUnlockEntry = {
let v = RolePhotoUnlockEntryView()
bottomGradientOperateStackV.addArrangedSubview(v)
return v
}()
setDefaultEntry = {
let v = RolePhotoSetDefaultEntryView()
bottomGradientOperateStackV.addArrangedSubview(v)
return v
}()
moreButton = {
let v = EPIconGhostButton(radius: .none, iconSize: .medium, iconCode: .more)
v.addTarget(self, action: #selector(tapNaviMoreInMyAIAlbum(sender:)), for: .touchUpInside)
titleView.rightStackH.addArrangedSubview(v)
titleView.paddingRightForRightStack = 16
v.snp.makeConstraints { make in
make.size.equalTo(v.bgImageSize())
}
return v
}()
setupRoleEvents()
}
func setupRoleEvents() {
rolePhotoUnlockEntry.editUnlockWayAction = { [weak self] in
self?.tapToSetupUnlockWay()
}
setDefaultEntry.setButton.addTarget(self, action: #selector(tapSetRoleDefaultButton), for: .touchUpInside)
}
// MARK: Action
func tapToSetupUnlockWay() {
let vc = RolePhotoUnlockWaySetController()
// item
let imageModel = imageModels[currentIndex]
vc.browseModel = imageModel
vc.priceUpdateAction = { [weak self] price in
let unlockPrice = price ?? 0
imageModel.aiAlbum.unlockPrice = unlockPrice
if unlockPrice > 0 {
imageModel.aiAlbum.isDefault = false
}
self?.reloadStatesByModel(model: imageModel)
}
navigationController?.pushViewController(vc, animated: true)
}
@objc func tapNaviMoreInMyAIAlbum(sender: UIButton) {
let pop = CLPopoverListView()
let rect = view.convert(sender.frame, from: sender.superview)
pop.setupDeletePopover(rect.insetBy(dx: 0.0, dy: -6.0), inView: view) { [weak self] in
self?.deleteAlbumOfMyAIRoleTapAction()
}
}
@objc private func tapSetRoleDefaultButton() {
let imageModel = imageModels[currentIndex]
let unlockPrice = imageModel.aiAlbum.unlockPrice
if unlockPrice > 0{
let alert = Alert(title: "默认图片", text: "设置为默认图片后,图片的解锁方式只能为“免费”")
let action1 = AlertAction(title: "Confirm", actionStyle: .confirm) {[weak self] in
self?.doRequestSetRoleDefaultAlbum()
}
let action2 = AlertAction(title: "Cancel", actionStyle: .cancel)
alert.addAction(action1)
alert.addAction(action2)
alert.show()
}else{
doRequestSetRoleDefaultAlbum()
}
}
// MARK: Functions
private func doRequestSetRoleDefaultAlbum(){
let imageModel = imageModels[currentIndex]
let aiUid = imageModel.aiId
let albumId = imageModel.aiAlbum.albumId
Hud.showIndicator()
AIRoleProvider.request(.aiRolePhotoDefaultSet(aiUid: aiUid, albumId: albumId), modelType: AnyCodable.self) { [weak self] result in
Hud.hideIndicator()
switch result {
case .success:
// dlog("set default results")
imageModel.aiAlbum.isDefault = true
self?.reloadStatesByModel(model: imageModel)
self?.setDefaultEntry.setupIsDefault(true)
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged)
NotificationCenter.post(name: .aiRoleInfoChanged) //
case .failure:
break
}
}
}
@objc func deleteAlbumOfMyAIRoleTapAction() {
guard currentIndex >= 0, currentIndex < imageModels.count else { return }
let model = imageModels[currentIndex]
if model.aiAlbum.isDefault.boolValue{
let alert = Alert(title: "删除图片", text: "不可删除封面默认图片,该图片会作为在个人主页头图,卡片主图,聊天背景")
let action1 = AlertAction(title: "Got it", actionStyle: .confirm)
alert .addAction(action1)
alert.show()
return
}
let alert = Alert(title: "删除图片", text: "图片删除后不可恢复。已经付费解锁过该图片的用户依然可以在角色的相册中看到该图片。")
let action1 = AlertAction(title: "Delete", actionStyle: .destructive) {[weak self] in
self?.deleteTapActionDone()
}
let action2 = AlertAction(title: "Cancel", actionStyle: .cancel)
alert.addAction(action1)
alert.addAction(action2)
alert.show()
}
private func deleteTapActionDone() {
let model = imageModels[currentIndex]
model.deleteTapBlock?(model) { [weak self] isSuccess in
guard let self = self else { return }
if isSuccess {
self.imageModels.remove(at: self.currentIndex)
if self.imageModels.isEmpty {
PhotoBrowserManager.shared.hidePhotoBrowser()
} else {
if self.currentIndex >= self.imageModels.count {
self.currentIndex -= 1
}
self.setupViews()
self.reloadCountLabel(hidden: false)
}
}
}
}
// MARK: - 🚩Other's Role
func createOperateViewOfOthers() {
roleOthersContainer = {
let v = SelectiveDeliveryEventsView()
v.backgroundColor = .clear
view.insertSubview(v, belowSubview: titleView)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
// roleOthersContainer?.isUserInteractionEnabled = false
roleOthersCenterLock = {
let v = UIImageView()
v.image = MWIconFont.image(fromIcon: .iconPrivate, size: CGSize(width: 40, height: 40), color: .white)
roleOthersContainer?.addSubview(v)
v.snp.makeConstraints { make in
make.center.equalToSuperview()
}
return v
}()
let bottomStackH = {
let v = UIStackView()
v.spacing = 48
v.alignment = .center
roleOthersContainer?.addSubview(v)
v.snp.makeConstraints { make in
make.height.equalTo(48)
make.bottom.equalToSuperview().offset(-16 - UIWindow.safeAreaBottom * 0.5)
make.trailing.equalToSuperview().offset(-24)
}
return v
}()
iconUnlockButton = {
let v = StyleButton()
v.setContentHuggingPriority(UILayoutPriority(rawValue: 246), for: .horizontal)
v.primary(size: .large)
v.addTarget(self, action: #selector(tapUnlockPhoto), for: .touchUpInside)
bottomStackH.addArrangedSubview(v)
return v
}()
iconLabel = {
let v = CLIconLabel()
v.iconImageView.image = UIImage.icon32Diamond
v.iconSize = CGSize(width: 20, height: 20)
roleOthersContainer?.addSubview(v)
v.snp.makeConstraints { make in
make.centerY.equalTo(bottomStackH)
make.leading.equalToSuperview().offset(24)
make.trailing.lessThanOrEqualTo(bottomStackH.snp.leading).offset(-8)
}
return v
}()
iconLabel?.contentLabel.text = "1234"
let attributeString = StyleButton.getUnlockAttributeTitleByCoin(coin: 123, string: "unlock")
iconUnlockButton?.setAttributedTitle(attributeString, for: .normal)
}
@objc func tapUnlockPhoto() {
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
PhotoBrowserManager.shared.hidePhotoBrowser()
return
}
let photoModel = imageModels[currentIndex]
var params = [String: Any]()
if let album = photoModel.aiAlbum {
if let aiId = photoModel.aiId {
params.updateValue(aiId, forKey: "aiId")
}
let albumId = album.albumId
params.updateValue(albumId, forKey: "albumId")
} else if let model = photoModel.sessionModel {
if let aiId = photoModel.aiId {
params.updateValue(aiId, forKey: "aiId")
}
if let albumId = model.baseRemoteInfo?.customAttachment?.albumId {
params.updateValue(albumId, forKey: "albumId")
}
if let messageServerId = model.v2msg?.messageServerId {
params.updateValue(messageServerId, forKey: "messageServerId")
}
} else {
return
}
//
let imgTest = "https://hhb.crushlevel.ai/dev/role/17581021489486439.jpg"
// if var album = photoModel.aiAlbum{
//
// album.lockStatus = .unlock
// album.imgUrl = nil
// album.img1 = "https://sub.crushlevel.ai/files/b/test/439076604280833/0aec65fdd92c404a9e3f8acac8e2c1ba.jpg?x-oss-process=image/resize,w_468,h_600&v=1&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9zdWIuY3J1c2hsZXZlbC5haS9maWxlcy9iL3Rlc3QvNDM5MDc2NjA0MjgwODMzLzBhZWM2NWZkZDkyYzQwNGE5ZTNmOGFjYWM4ZTJjMWJhLmpwZz94LW9zcy1wcm9jZXNzPWltYWdlL3Jlc2l6ZSx3XzQ2OCxoXzYwMCZ2PTEiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE3NTgyMjgzNjd9fX1dfQ__&Signature=Jv5jE4d072OkFyYq5dxa3unXVaLWSNRddJEIIm42j4zmg36Yq8HGxVXz4X954ERmujm8zCluiVGMbIx-EH9JlQ1s~zbhgOo-lliaDGl977EsCVLBPsf639WFpdCXqnf3QAM7LwhuCbmdi~PBybJhKS31nEKoS53idOB4JyEXXp9wv3RpVjDoL4JF8C22H8k5gJ0hpt3NhfZiTSbsSRJBApNHfCKAFm6PEKQ8dAQ6f7rRxHwPTkbhHi~fRUahuJI10Ti-8t2Hem4akTV4plmgz9chsLCfHBNh5WDrwzoCZRDDljpaNcwpkZ5Mew23seKphb5iLxHgVP3WGAwXb0BoRA__&Key-Pair-Id=K35ZQ246Y37QV8"
// photoModel.imageUrl = album.img1
// album.unlockPrice = 0
// photoModel.aiAlbum = album
// self.reloadStates(index: self.currentIndex)
// self.reloadCurrentZoomImage()
// }
// return
// #warning("test")
// if let model = photoModel.sessionModel {
// Hud.hideInidcator()
// model.baseRemoteInfo?.customAttachment?.unlockPrice = 0
// model.baseRemoteInfo?.customAttachment?.url = imgTest
//
// photoModel.imageUrl = imgTest
// photoModel.sessionModel = model
//
// // Reload
// self.reloadStates(index: self.currentIndex)
// self.reloadCurrentZoomImage()
// }
// return
Hud.showIndicator()
ChatProvider.request(.aiUnlockAlbumImg(params: params), modelType: AIAlbumUnlockImages.self) { [weak self] result in
Hud.hideIndicator()
switch result {
case let .success(unlockData):
guard let img1 = unlockData?.img1 else {
PhotoBrowserManager.shared.hidePhotoBrowser()
return
}
// 🚩"1.2.UI"
//
guard let self = self else { return }
if let album = photoModel.aiAlbum {
album.lockStatus = .unlock
album.img1 = img1
album.imgUrl = img1
album.unlockPrice = 0
photoModel.imageUrl = album.img1
photoModel.aiAlbum = album
// Reload
self.reloadStates(index: self.currentIndex)
self.reloadCurrentZoomImage()
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged, object: album)
}else if let model = photoModel.sessionModel {
model.baseRemoteInfo?.customAttachment?.unlockPrice = 0
model.baseRemoteInfo?.customAttachment?.url = img1
photoModel.imageUrl = img1
photoModel.sessionModel = model
// Reload
self.reloadStates(index: self.currentIndex)
self.reloadCurrentZoomImage()
NotificationCenter.post(name: .aiRoleAlbumPhotoInfoChanged, object: model)
}else{
assert(false, "need update")
}
WalletCore.shared.refreshWallet()
case .failure:
break
}
}
}
@objc func tapOperateChipButton(_ sender: EPChipContrastButton) {
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
PhotoBrowserManager.shared.hidePhotoBrowser()
return
}
}
@objc func tapLikeButton() {
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
PhotoBrowserManager.shared.hidePhotoBrowser()
return
}
let photoModel = imageModels[currentIndex]
guard let likeView = likeView else { return }
// IM
if let album = photoModel.aiAlbum {
let albumId = album.albumId
if album.likedStatus == .liked {
//
album.likedStatus = .cancel
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
PhotosViewModel.shared.album = album
likeView.bind(aiAlbum: 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 { _ in
guard var album = photoModel.aiAlbum else { return }
album.likedStatus = .liked
album.likedCount = (album.likedCount ?? 0) + 1
PhotosViewModel.shared.album = album
likeView.bind(aiAlbum: 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
let photoModel = imageModels[currentIndex]
guard let likeView = likeView, let album = photoModel.aiAlbum else { return }
likeView.likeButton.isEnabled = true
switch result {
case .success:
//
break
case .failure:
//
if isLike {
//
album.likedStatus = .cancel
album.likedCount = max((album.likedCount ?? 0) - 1, 0)
} else {
//
album.likedStatus = .liked
album.likedCount = (album.likedCount ?? 0) + 1
}
PhotosViewModel.shared.album = album
likeView.bind(aiAlbum: album)
}
}
// MARK: - Helper
/// like : 💎 20 unlock
func getUnlockAttributeTitleByCoin(coin: Int) -> NSAttributedString {
let text = " \(coin) unlock"
let attributedString = NSMutableAttributedString()
if let iconImage = UIImage(named: "icon_32_diamond") { //
let attachment = NSTextAttachment()
attachment.image = iconImage
let iconSize = CGSize(width: 24, height: 24) //
attachment.bounds = CGRect(origin: .init(x: 0, y: -4), size: iconSize)
let iconAttributedString = NSAttributedString(attachment: attachment)
attributedString.append(iconAttributedString)
}
//
let textAttributedString = text.withAttributes([
.font(.t.tll), //
.textColor(.white),
])
attributedString.append(textAttributedString)
return attributedString
}
}