575 lines
20 KiB
Swift
575 lines
20 KiB
Swift
//
|
||
// HomePageRootView.swift
|
||
// Crush
|
||
//
|
||
// Created by Leon on 2025/7/22.
|
||
//
|
||
|
||
import UIKit
|
||
|
||
class HomePageRootView: UIView {
|
||
var emptyView: UIView!
|
||
|
||
private var cardContainer: UIView!
|
||
private var bgTopIv: UIImageView!
|
||
private var dragCardContainer: MeetDragCardContainer!
|
||
private var dataArray: [MeetCard] = []
|
||
|
||
|
||
// Flag
|
||
var swipeCardCount: Int = 0 // 计数
|
||
|
||
weak var viewModel: MeetViewModel!
|
||
weak var weakGiftSheet: GiftAIRoleSheet?
|
||
|
||
override init(frame: CGRect) {
|
||
super.init(frame: frame)
|
||
setupViews()
|
||
setupData()
|
||
setupEvent()
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
fatalError("init(coder:) has not been implemented")
|
||
}
|
||
|
||
private func setupViews() {
|
||
|
||
emptyView = {
|
||
let v = UIView()
|
||
v.showEmpty(text: "暂无卡片")
|
||
addSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.leading.trailing.equalToSuperview()
|
||
make.bottom.equalToSuperview().offset(-UIWindow.tabBarTotalHeight)
|
||
make.top.equalToSuperview().offset(UIWindow.navBarTotalHeight)
|
||
}
|
||
return v
|
||
}()
|
||
|
||
cardContainer = {
|
||
let v = UIView()
|
||
addSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview()
|
||
}
|
||
return v
|
||
}()
|
||
|
||
// 创建拖拽卡片容器
|
||
bgTopIv = {
|
||
let v = UIImageView()
|
||
v.image = UIImage(named: "meet_top_bg")
|
||
cardContainer.addSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.top.leading.trailing.equalToSuperview()
|
||
make.height.equalTo(v.snp.width).multipliedBy(200/393.0)
|
||
}
|
||
return v
|
||
}()
|
||
|
||
let cardWidth = EncounterAICardView.cardWidth
|
||
let cardHeight = EncounterAICardView.cardHeight
|
||
dragCardContainer = MeetDragCardContainer(frame: CGRect(x: 0, y: 0, width: cardWidth, height: cardHeight))
|
||
cardContainer.addSubview(dragCardContainer)
|
||
|
||
dragCardContainer.snp.makeConstraints { make in
|
||
make.centerX.equalToSuperview()
|
||
make.top.equalToSuperview().offset(UIWindow.navBarTotalHeight + 12)
|
||
make.width.equalTo(cardWidth)
|
||
make.height.equalTo(cardHeight)
|
||
}
|
||
|
||
// 设置数据源和代理
|
||
dragCardContainer.dataSource = self
|
||
dragCardContainer.delegate = self
|
||
|
||
// 初始状态都隐藏
|
||
emptyView.isHidden = true
|
||
//cardContainer.isHidden = true
|
||
}
|
||
|
||
private func setupData(){
|
||
setupDragCardContainer()
|
||
}
|
||
|
||
private func setupEvent(){
|
||
|
||
}
|
||
|
||
private func setupDragCardContainer() {
|
||
// 重新加载数据
|
||
dragCardContainer.reloadData()
|
||
}
|
||
|
||
// MARK: - mark
|
||
|
||
func setupViewModel(vm: MeetViewModel){
|
||
viewModel = vm
|
||
// 绑定ViewModel回调
|
||
viewModel?.onCardsLoaded = { [weak self] cards in
|
||
self?.dataArray = cards
|
||
self?.dragCardContainer.reloadData()
|
||
|
||
if self?.viewModel.requestParams.pn == 1{
|
||
self?.showEmptyPlaceholder(empty: cards.count == 0)
|
||
}
|
||
}
|
||
|
||
viewModel?.onCardsMoreLoaded = { [weak self] cards in
|
||
if cards.count == 0 {
|
||
self?.showEmptyPlaceholder(empty: true)
|
||
}
|
||
}
|
||
|
||
viewModel?.onLoadError = { error in
|
||
dlog("Meet加载卡片失败: \(error)")
|
||
}
|
||
}
|
||
|
||
// MARK: - Functions
|
||
|
||
private func doReportLike(card: MeetCard?){
|
||
guard let aiId = card?.aiId else {return}
|
||
|
||
swipeCardCount += 1
|
||
|
||
var params = [String:Any]()
|
||
params.updateValue(aiId, forKey: "aiId")
|
||
params.updateValue(true, forKey: "lk")
|
||
|
||
DiscoverProvider.request(.meetLikeOrReport(params: params), modelType: MeetCardReportResponse.self) {[weak self] result in
|
||
switch result {
|
||
case .success(let model):
|
||
self?.dealLikeAfter(aiId: aiId,card: card, obj: model)
|
||
case .failure:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
private func doReportDislike(card: MeetCard?){
|
||
guard let aiId = card?.aiId else {return}
|
||
|
||
swipeCardCount += 1
|
||
|
||
var params = [String:Any]()
|
||
params.updateValue(aiId, forKey: "aiId")
|
||
params.updateValue(true, forKey: "lk")
|
||
|
||
DiscoverProvider.request(.meetLikeOrReport(params: params), modelType: MeetCardReportResponse.self) {result in
|
||
switch result {
|
||
case .success:
|
||
break // do nothing
|
||
case .failure:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
private func dealLikeAfter(aiId: Int, card: MeetCard?, obj:MeetCardReportResponse?){
|
||
guard let response = obj else {return}
|
||
// ...
|
||
if response.bd.boolValue {
|
||
// #warning("test")
|
||
// let vc = MeetMatchedController()
|
||
// vc.card = card!
|
||
//// vc.modalPresentationStyle = .fullScreen
|
||
// let navc = CLNavigationController(rootViewController: vc)
|
||
//// self?.viewController()?.present(navc, animated: true)
|
||
// UIWindow.getTopViewController()?.present(navc, animated: true)
|
||
// return
|
||
// 调用绑定
|
||
DiscoverProvider.request(.meetReportBind(aiId: aiId), modelType: MeetMatchInfo.self) { result in
|
||
switch result {
|
||
case .success(let model):
|
||
if let resultObj = model{
|
||
let vc = MeetMatchedController()
|
||
vc.info = resultObj
|
||
let navc = CLNavigationController(rootViewController: vc)
|
||
UIWindow.getTopViewController()?.present(navc, animated: true)
|
||
}else{
|
||
dlog("❌meetReportBind result is nil")
|
||
let vc = MeetMatchedController()
|
||
vc.card = card!
|
||
let navc = CLNavigationController(rootViewController: vc)
|
||
// self?.viewController()?.present(navc, animated: true)
|
||
UIWindow.getTopViewController()?.present(navc, animated: true)
|
||
}
|
||
case .failure:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
if response.rc.boolValue{
|
||
DiscoverProvider.request(.meetRcAndRetrunBlurAlbum, modelType: MeetReportAdmirerReturnAlbum.self) {[weak self] result in
|
||
switch result {
|
||
case .success(let model):
|
||
self?.doShowSecretAdmirerAlert(aiId: aiId, photo: model)
|
||
case .failure:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private func doShowSecretAdmirerAlert(aiId: Int?, photo: MeetReportAdmirerReturnAlbum?){
|
||
guard let thePhoto = photo else {return}
|
||
|
||
let content = "Someone is secretly in love with you\n"
|
||
let alert = Alert(title: "Secret Admirer", text: content, image: UIImage(named: "heart_meet_48")!)
|
||
|
||
alert.masTopToImageBgForImageView?.update(offset: 42)
|
||
alert.setupContentStackSpacing(14)
|
||
alert.setupBottomBlurImageUrl(url: thePhoto.img1)
|
||
|
||
//let coin = Coin(cents: thePhoto.unlockPrice)
|
||
let coin = Coin(cents: 5000) // 50 coin
|
||
let string = "\(coin.formatted) unlock"
|
||
let aString = NSAttributedString.getIconTitleAttributeByWords(words: string, iconImage: UIImage.icon32Diamond, iconSize: CGSize(width: 24, height: 24), textFont: .t.tll, textColor: .white)
|
||
let confirmCoin = AlertAction(attributedTitle: aString, actionStyle: .confirm) {[weak self] in
|
||
// 解锁,🔓
|
||
self?.doUnlockLikeYou(aiId: aiId, albumId: photo?.albumId)
|
||
}
|
||
|
||
let cancel = AlertAction(title: "Cancel", actionStyle: .cancel, block: nil)
|
||
|
||
alert.addAction(confirmCoin)
|
||
alert.addAction(cancel)
|
||
alert.show()
|
||
alert.layoutIfNeeded()
|
||
}
|
||
|
||
private func doUnlockLikeYou(aiId: Int? , albumId: Int?){
|
||
guard let theAIid = aiId, let theAlbumId = albumId else {
|
||
return
|
||
}
|
||
|
||
Hud.showIndicator()
|
||
DiscoverProvider.request(.meetUnlockLikeYou(aiId: theAIid, albumId: theAlbumId), modelType: AIAlbumUnlockImages.self) {[weak self] result in
|
||
switch result {
|
||
case .success:
|
||
self?.doGetLikeYouAICardInfo(aiId: theAIid)
|
||
case .failure:
|
||
Hud.hideIndicator()
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
func doGetLikeYouAICardInfo(aiId: Int?){
|
||
guard let theAiId = aiId else{
|
||
Hud.hideIndicator()
|
||
return
|
||
}
|
||
|
||
DiscoverProvider.request(.meetCardDetail(aiId: theAiId), modelType: MeetCard.self) {[weak self] result in
|
||
Hud.hideIndicator()
|
||
switch result {
|
||
case .success(let model):
|
||
model?.secretAdmirer = true
|
||
self?.doRestoreCard(card: model)
|
||
case .failure:
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
private func doRestoreCard(card : MeetCard?){
|
||
guard let data = card else {return}
|
||
if let tmpStoreNopeCardView = dragCardContainer.tmpStoreNopeCardView as? EncounterAICardView{
|
||
tmpStoreNopeCardView.config(data)
|
||
dragCardContainer.addCardView(tmpStoreNopeCardView, fromDirection: .default)
|
||
}else{
|
||
dlog("❌ none tmpStoreNopeCardView")
|
||
}
|
||
}
|
||
|
||
// MARK: - Helper
|
||
|
||
func showEmptyPlaceholder(empty: Bool){
|
||
emptyView.isHidden = !empty
|
||
cardContainer.isHidden = empty
|
||
}
|
||
|
||
// MARK: - Test
|
||
|
||
func testFunction(){
|
||
doGetLikeYouAICardInfo(aiId: 444190968774657)
|
||
}
|
||
|
||
}
|
||
|
||
// MARK: - EncounterAICardViewDelegate
|
||
extension HomePageRootView: EncounterAICardViewDelegate {
|
||
func cardViewTapLike(_ obj: MeetCard?) {
|
||
print("点击了喜欢按钮: \(String(describing: obj?.nickname))")
|
||
if UserCore.shared.isLogin() == false && swipeCardCount >= 3{
|
||
UserCore.shared.checkUserLoginIfNotPushUserToLogin()
|
||
return
|
||
}
|
||
|
||
dragCardContainer.removeCardViewForDirection(.right)
|
||
doReportLike(card: obj)
|
||
}
|
||
|
||
func cardViewTapGift(_ obj: MeetCard?) {
|
||
// print("点击了礼物按钮: \(String(describing: obj?.nickname))")
|
||
guard UserCore.shared.checkUserLoginIfNotPushUserToLogin() else{
|
||
return
|
||
}
|
||
|
||
let vc = GiftAIRoleSheet()
|
||
vc.giftView.delegate = self
|
||
vc.giftView.targetHeartbeatValue = obj?.heartbeatVal ?? 0
|
||
weakGiftSheet = vc
|
||
vc.show()
|
||
}
|
||
|
||
func cardViewTapDislike(_ obj: MeetCard?) {
|
||
print("点击了不喜欢按钮: \(String(describing: obj?.nickname))")
|
||
if UserCore.shared.isLogin() == false && swipeCardCount >= 3{
|
||
UserCore.shared.checkUserLoginIfNotPushUserToLogin()
|
||
return
|
||
}
|
||
|
||
dragCardContainer.removeCardViewForDirection(.left)
|
||
doReportDislike(card: obj)
|
||
}
|
||
|
||
func cardViewTapHeader(_ obj: MeetCard?, cardView: EncounterAICardView?){
|
||
guard let data = obj, let albumList = data.albumList, let aiId = obj?.aiId else{return}
|
||
|
||
let screenRect = cardView?.screenRect ?? .zero
|
||
let currentImageUrl = obj?.imageUrl ?? ""
|
||
|
||
var photoModels = [PhotoBrowserModel]()
|
||
|
||
var browseIndex = 0
|
||
for (index, per) in albumList.enumerated() {
|
||
let model = PhotoBrowserModel()
|
||
model.aiAlbum = per
|
||
|
||
model.aiId = aiId
|
||
model.imageUrl = per.getImgUrl()
|
||
model.image = cardView?.header.imageView.image ?? UIImage()
|
||
model.sourceRect = screenRect
|
||
|
||
if model.imageUrl == currentImageUrl{
|
||
browseIndex = index
|
||
}
|
||
|
||
photoModels.append(model)
|
||
}
|
||
|
||
ImageBrowser.show(models: photoModels, index: browseIndex, type: .roleOthersInAlbum)
|
||
}
|
||
}
|
||
|
||
extension HomePageRootView: GiftGridSendViewDelegate{ func giftSend(giftId: Int, gift: GiftDictModel, num: Int){
|
||
guard let card = dragCardContainer.getCurrentShowCardView() as? EncounterAICardView, let info = card.card else{
|
||
return
|
||
}
|
||
guard let aiId = info.aiId else{
|
||
return
|
||
}
|
||
|
||
#warning("test")
|
||
weakGiftSheet?.dismiss()
|
||
dragCardContainer.removeCardViewForDirection(.right)
|
||
let vc = MeetMatchedController()
|
||
vc.card = info
|
||
vc.gift = gift
|
||
vc.giftCount = num
|
||
let navc = CLNavigationController(rootViewController: vc)
|
||
UIWindow.getTopViewController()?.present(navc, animated: true)
|
||
return
|
||
|
||
// var params = [String: Any]()
|
||
//
|
||
// params.updateValue(aiId, forKey: "aiId")
|
||
// params.updateValue(giftId, forKey: "giftId")
|
||
// params.updateValue(num, forKey: "num")
|
||
// params.updateValue("HOME", forKey: "scene")
|
||
//
|
||
// Hud.showIndicator()
|
||
// ChatProvider.request(.aiUserGiftSend(params: params), modelType: EmptyModel.self) {[weak self] result in
|
||
// Hud.hideIndicator()
|
||
// switch result {
|
||
// case .success:
|
||
// self?.weakGiftSheet?.dismiss()
|
||
//
|
||
// self?.dragCardContainer.removeCardViewForDirection(.right)
|
||
// let vc = MeetMatchedController()
|
||
// vc.card = info
|
||
// vc.gift = gift
|
||
// vc.giftCount = num
|
||
// let navc = CLNavigationController(rootViewController: vc)
|
||
// UIWindow.getTopViewController()?.present(navc, animated: true)
|
||
// case .failure:
|
||
// break
|
||
// }
|
||
// }
|
||
}
|
||
|
||
func giftGoHeartbeatPage(){
|
||
guard let card = dragCardContainer.getCurrentShowCardView() as? EncounterAICardView, let info = card.card else{
|
||
return
|
||
}
|
||
guard let aiId = info.aiId else{
|
||
return
|
||
}
|
||
weakGiftSheet?.dismiss()
|
||
AppRouter.goAIHeartBeatLevelPage(aiId: aiId)
|
||
}
|
||
|
||
func giftGoVIPCenter(){
|
||
weakGiftSheet?.dismiss()
|
||
AppRouter.goVIPCenter()
|
||
}
|
||
|
||
func giftNumPick(num: Int){
|
||
guard let window = UIWindow.getTopDisplayWindow(), let sheet = weakGiftSheet else { return } // 🔥 Assuming topDisplayWindow is a custom UIView extension method
|
||
|
||
guard let giftSendView = sheet.giftView else{
|
||
return
|
||
}
|
||
|
||
let rect1 = giftSendView.countImg.convert(giftSendView.countImg.frame, from: giftSendView.countImg.superview)
|
||
let rect2 = giftSendView.countImg.convert(rect1, to: window)
|
||
|
||
let vc = GiftCountChooseController(sourceRect: rect2, selectedValue: "\(num)")
|
||
vc.chooseBlock = { [weak self] count in
|
||
// ... Handle count selection
|
||
self?.weakGiftSheet?.giftView.num = Int(count) ?? 1
|
||
}
|
||
|
||
vc.popoverDismiss = { [weak self] in
|
||
// ... Handle popover dismissal
|
||
self?.weakGiftSheet?.giftView.countImg.transform = .identity
|
||
}
|
||
|
||
viewController()?.navigationController?.addChild(vc)
|
||
sheet.addSubview(vc.view)
|
||
|
||
UIView.animate(withDuration: 0.2) { [weak self] in
|
||
self?.weakGiftSheet?.giftView.countImg.transform = CGAffineTransform(rotationAngle: .pi)
|
||
}
|
||
}
|
||
}
|
||
|
||
extension HomePageRootView :MeetDragCardContainerDataSource {
|
||
func numberOfRowsInYFLDragCardContainer(_ container: MeetDragCardContainer) -> Int {
|
||
return dataArray.count
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, viewForRowsAt index: Int) -> MeetDragCardView {
|
||
dlog("🐟index:\(index)")
|
||
let cardView = EncounterAICardView()
|
||
let card = dataArray[index]
|
||
cardView.config(card)
|
||
cardView.delegate = self
|
||
return cardView
|
||
}
|
||
}
|
||
|
||
// MARK: - MeetDragCardContainerDelegate
|
||
|
||
extension HomePageRootView: MeetDragCardContainerDelegate {
|
||
func container(_ container: MeetDragCardContainer, didSelectRowAt index: Int) {
|
||
print("「Meet」点击了整体卡片: \(index)")
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, dataSourceIsEmpty isEmpty: Bool) {
|
||
if isEmpty {
|
||
print("「Meet」数据源为空,可以加载更多数据")
|
||
// 这里可以加载更多数据
|
||
|
||
if viewModel.cards.count > 0{ // 说明是后续加载
|
||
loadMoreData()
|
||
// showEmptyPlaceholder(empty: true)
|
||
}
|
||
}
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, canDragForCardView cardView: MeetDragCardView) -> Bool {
|
||
return true
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, dargingForCardView cardView: MeetDragCardView, direction: ContainerDragDirection, widthRate: CGFloat, heightRate: CGFloat) {
|
||
// 拖拽过程中的回调
|
||
if direction == .left {
|
||
container.showNopeLogo(true, widthRate: CGFloat(abs(widthRate)))
|
||
print("🐟左滑ing \(widthRate)")
|
||
} else if direction == .right {
|
||
container.showLikeLogo(true, widthRate: CGFloat(abs(widthRate)))
|
||
print("🐟右滑ing \(widthRate)")
|
||
} else {
|
||
container.showNopeLogo(false, widthRate: 0)
|
||
container.showLikeLogo(false, widthRate: 0)
|
||
}
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, canDragFinishForDirection direction: ContainerDragDirection, forCardView cardView: MeetDragCardView) -> Bool {
|
||
if UserCore.shared.isLogin(){
|
||
return true
|
||
}
|
||
|
||
if swipeCardCount >= 3{
|
||
return UserCore.shared.checkUserLoginIfNotPushUserToLogin()
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, dragDidFinshForDirection direction: ContainerDragDirection, forCardView cardView: MeetDragCardView) {
|
||
print("🐟卡片拖拽完成,方向: \(direction)")
|
||
let aiCardView = cardView as! EncounterAICardView
|
||
// 显示相应的动画
|
||
switch direction {
|
||
case .left:
|
||
//container.showNopeLottie()
|
||
container.showNopeLogo()
|
||
doReportDislike(card: aiCardView.card)
|
||
case .right:
|
||
//container.showLikeLottie()
|
||
container.showLikeLogo()
|
||
doReportLike(card: aiCardView.card)
|
||
default:
|
||
break
|
||
}
|
||
|
||
// 检查是否需要预加载
|
||
checkAndPreloadIfNeeded()
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, lookingBack direction: ContainerDragDirection, forCardView cardView: MeetDragCardView) {
|
||
print("🐟卡片回看,方向: \(direction)")
|
||
}
|
||
|
||
func container(_ container: MeetDragCardContainer, enterSmallCardMode smallCardMode: Bool, forCardView cardView: MeetDragCardView) {
|
||
print("🐟进入小卡片模式: \(smallCardMode)")
|
||
}
|
||
|
||
private func loadMoreData() {
|
||
dlog("🐟try load more datas")
|
||
// 加载更多数据
|
||
viewModel?.loadMoreCards()
|
||
}
|
||
|
||
// 检查并预加载数据
|
||
private func checkAndPreloadIfNeeded() {
|
||
guard let viewModel = viewModel else { return }
|
||
|
||
// 计算剩余卡片数量
|
||
let remainingCount = dataArray.count - dragCardContainer.getCurrentShowCardViewIndex()
|
||
|
||
// 如果剩余卡片数量少于等于5张,且不在加载中,则预加载
|
||
if viewModel.shouldPreload(remainingCount: remainingCount) {
|
||
dlog("🐟预加载数据,剩余卡片数量: \(remainingCount)")
|
||
loadMoreData()
|
||
}
|
||
}
|
||
}
|