187 lines
5.7 KiB
Swift
187 lines
5.7 KiB
Swift
//
|
||
// EncounterAICardView.swift
|
||
// Crush
|
||
//
|
||
// Created by Leon on 2025/9/10.
|
||
//
|
||
|
||
import UIKit
|
||
import Combine
|
||
|
||
protocol EncounterAICardViewDelegate: AnyObject{
|
||
func cardViewTapLike(_ obj: MeetCard?)
|
||
func cardViewTapGift(_ obj: MeetCard?)
|
||
func cardViewTapDislike(_ obj: MeetCard?)
|
||
func cardViewTapHeader(_ obj: MeetCard?, cardView: EncounterAICardView?)
|
||
}
|
||
|
||
class EncounterAICardView: MeetDragCardView {
|
||
|
||
static let cardWidth = UIScreen.width - 12 * 2.0
|
||
static let cardHeight = UIScreen.height - UIWindow.tabBarTotalHeight - UIWindow.navBarTotalHeight - 12 - 12
|
||
|
||
var scrollContainer: LTScrollContainer!
|
||
var indicator: PageIndicatorView!
|
||
|
||
var header: EncounterAICardHeader!
|
||
var albumView: EncounterAICardAlbumView!
|
||
|
||
weak var delegate : EncounterAICardViewDelegate?
|
||
|
||
var card: MeetCard?
|
||
|
||
// Flag
|
||
var isPullingToAIHomePage = false
|
||
|
||
private var cancellables = Set<AnyCancellable>()
|
||
|
||
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() {
|
||
backgroundColor = .c.cbd
|
||
|
||
scrollContainer = {
|
||
let v = LTScrollContainer()
|
||
v.scrollView.delegate = self
|
||
v.scrollView.bounces = true
|
||
v.scrollView.showsVerticalScrollIndicator = false
|
||
addSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.edges.equalToSuperview()
|
||
}
|
||
return v
|
||
}()
|
||
|
||
indicator = {
|
||
let v = PageIndicatorView()
|
||
addSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.centerY.equalToSuperview()
|
||
make.trailing.equalToSuperview().offset(-4)
|
||
}
|
||
return v
|
||
}()
|
||
|
||
header = {
|
||
let v = EncounterAICardHeader()
|
||
scrollContainer.stack.addArrangedSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.leading.trailing.equalToSuperview()
|
||
}
|
||
return v
|
||
}()
|
||
|
||
albumView = {
|
||
let v = EncounterAICardAlbumView()
|
||
scrollContainer.stack.addArrangedSubview(v)
|
||
v.snp.makeConstraints { make in
|
||
make.leading.trailing.equalToSuperview()
|
||
}
|
||
return v
|
||
}()
|
||
}
|
||
|
||
private func setupData(){
|
||
|
||
}
|
||
|
||
private func setupEvent(){
|
||
header.dislikeButton.addTarget(self, action: #selector(tapDislikeButton), for: .touchUpInside)
|
||
header.likeButton.addTarget(self, action: #selector(tapLikeButton), for: .touchUpInside)
|
||
header.giftButton.addTarget(self, action: #selector(tapGiftButton), for: .touchUpInside)
|
||
header.imageBgButton.addTarget(self, action: #selector(tapImageBgButton), for: .touchUpInside)
|
||
header.overlayBgButton.addTarget(self, action: #selector(tapImageBgButton), for: .touchUpInside)
|
||
|
||
PhotosViewModel.shared.$album.sink {[weak self] photo in
|
||
guard let self = self else{return}
|
||
guard let album = photo , let albumId = photo?.albumId else {return}
|
||
|
||
let albumList = self.card?.albumList ?? []
|
||
for per in albumList{
|
||
let perAlbum = per
|
||
if albumId == perAlbum.albumId{
|
||
perAlbum.updateFrom(album)
|
||
self.albumView.config(albumList)
|
||
break
|
||
}
|
||
}
|
||
}.store(in: &cancellables)
|
||
}
|
||
|
||
// MARK: - Public
|
||
|
||
func config(_ data: MeetCard?){
|
||
self.card = data
|
||
guard let card = data else { return }
|
||
|
||
// 配置Header数据
|
||
header.config(card)
|
||
|
||
// 配置相册数据
|
||
albumView.configCard(card: card)
|
||
albumView.config(card.albumList ?? [])
|
||
}
|
||
|
||
// MARK: - Action
|
||
|
||
@objc func tapDislikeButton(){
|
||
delegate?.cardViewTapDislike(card)
|
||
}
|
||
|
||
@objc func tapLikeButton(){
|
||
delegate?.cardViewTapLike(card)
|
||
}
|
||
|
||
@objc func tapGiftButton(){
|
||
delegate?.cardViewTapGift(card)
|
||
}
|
||
|
||
@objc func tapImageBgButton(){
|
||
delegate?.cardViewTapHeader(card, cardView: self)
|
||
}
|
||
}
|
||
|
||
extension EncounterAICardView: UIScrollViewDelegate{
|
||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||
// 计算滚动进度 (0.0 到 1.0)
|
||
let maxOffset = scrollView.contentSize.height - scrollView.bounds.size.height
|
||
let progress = maxOffset > 0 ? scrollView.contentOffset.y / maxOffset : 0
|
||
//dlog("progress:\(progress)")
|
||
// 更新指示器
|
||
//indicator.updateIndicator(progress: progress)
|
||
indicator.updateIndicator(top: progress >= 0.5)
|
||
}
|
||
|
||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||
let offsetY = scrollView.contentOffset.y
|
||
let contentHeight = scrollView.contentSize.height
|
||
let height = scrollView.frame.size.height
|
||
|
||
if offsetY > contentHeight - height + 40 {
|
||
|
||
guard let aiId = card?.aiId else{return}
|
||
//print("松手时,滑到底部之外了")
|
||
if isPullingToAIHomePage == false{
|
||
CLTool.feedbackGenerator()
|
||
AppRouter.goAIRoleHome(aiId: aiId)
|
||
|
||
isPullingToAIHomePage = true
|
||
}
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {[weak self] in
|
||
self?.isPullingToAIHomePage = false
|
||
}
|
||
} else if offsetY < 0 {
|
||
//print("松手时,滑到顶部之外了")
|
||
}
|
||
}
|
||
}
|