438 lines
17 KiB
Swift
438 lines
17 KiB
Swift
//
|
||
// 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
|
||
}
|
||
}
|