Visual_Novel_iOS/crush/Crush/Src/Modules/Home/View/EncounterAICardHeader.swift

452 lines
15 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.

//
// EncounterAICardHeader.swift
// Crush
//
// Created by Leon on 2025/9/11.
//
class EncounterAICardHeader:UIView{
var imageFieldContainer: UIView!
var imageBgButton: UIButton!
var imageView: UIImageView!
var topRightTag: EPTagLabel!
var overlay: GradientView!
var overlayBgButton: UIButton!
var bottomButtonsStackH : UIStackView!
var dislikeButton: UIButton!
var giftButton : EPIconPrimaryButton!
var likeButton : UIButton!
var likeAndCount: CLIconLabel!
var nameLabel: CLLabel!
var tagsStackH: UIStackView!
var introductionStackH: UIStackView!
var introductionLabel: LineSpaceLabel!
var introductionLabelTopButton: UIButton!
var expendButton: EPIconGhostButton!
var aiGeneratedLabel: CLLabel!
var albumTitleView: UIView!
var albumTitleLabel : CLLabel!
var data: MeetCard?
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
imageFieldContainer = {
let v = UIView()
v.backgroundColor = .clear
v.clipsToBounds = true
addSubview(v)
v.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(EncounterAICardView.cardHeight)
}
return v
}()
imageBgButton = {
let v = UIButton()
imageFieldContainer.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
imageView = {
let v = UIImageView()
v.contentMode = .scaleAspectFill
imageFieldContainer.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
topRightTag = {
let v = EPTagLabel(style: .primary, size: .large)
imageFieldContainer.addSubview(v)
v.snp.makeConstraints { make in
make.top.equalToSuperview().offset(24)
make.trailing.equalToSuperview().offset(-16)
}
return v
}()
overlay = {
let color = UIColor.c.cbd
let v = GradientView(colors: [color.withAlphaComponent(0), color.withAlphaComponent(0.6), color.withAlphaComponent(0.9)], gradientType: .topToBottom)
imageFieldContainer.addSubview(v)
v.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.bottom.equalToSuperview()
make.height.equalTo(368)
}
return v
}()
bottomButtonsStackH = {
let v = UIStackView()
v.spacing = 32
v.alignment = .center
imageFieldContainer.addSubview(v)
v.snp.makeConstraints { make in
make.bottom.equalToSuperview().offset(-40)
make.centerX.equalToSuperview()
}
return v
}()
dislikeButton = {
let v = UIButton()
let image = UIImage(named: "encounter_icon_dislike")
v.setImage(image, for: .normal)
v.backgroundColor = .c.cseln
v.cornerRadius = 32
v.contentMode = .center
bottomButtonsStackH.addArrangedSubview(v)
v.snp.makeConstraints { make in
make.size.equalTo(CGSize(width: 64, height: 64))
}
return v
}()
giftButton = {
let v = EPIconPrimaryButton(radius: .round, iconSize: .large, iconCode: .giftBorder)
bottomButtonsStackH.addArrangedSubview(v)
v.snp.makeConstraints { make in
make.size.equalTo(CGSize(width: 48, height: 48))
}
return v
}()
likeButton = {
let v = UIButton()
let image = UIImage(named: "encounter_icon_like")
v.setImage(image, for: .normal)
v.backgroundColor = .c.cseln
v.cornerRadius = 32
v.contentMode = .center
bottomButtonsStackH.addArrangedSubview(v)
v.snp.makeConstraints { make in
make.size.equalTo(CGSize(width: 64, height: 64))
}
return v
}()
setupMiddlePart()
setupAlbumTitlePart()
overlayBgButton = {
let v = UIButton()
overlay.insertSubview(v, at: 0)
v.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.bottom.equalTo(introductionStackH.snp.top).offset(-8)
}
return v
}()
// #warning("test")
// testData()
}
private func setupMiddlePart(){
nameLabel = {
let v = CLLabel()
v.numberOfLines = 1 // 1
v.font = .t.thl
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.trailing.equalToSuperview().offset(-96)
make.bottom.equalTo(overlay.snp.top).offset(112)
}
return v
}()
likeAndCount = {
let v = CLIconLabel()
v.iconSize = CGSize(width: 20, height: 20)
v.contentLabel.font = .t.tnds
v.iconImageView.image = MWIconFont.image(fromIcon: .like, size: CGSize(width: 20, height: 20), color: .white)
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-24)
make.centerY.equalTo(nameLabel)
}
return v
}()
tagsStackH = {
let v = UIStackView()
v.spacing = 8
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.top.equalTo(nameLabel.snp.bottom).offset(8)
}
return v
}()
introductionStackH = {
let v = UIStackView()
v.spacing = 0
v.alignment = .bottom
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.trailing.equalToSuperview().offset(-24)
make.top.equalTo(tagsStackH.snp.bottom).offset(8)
}
return v
}()
introductionLabel = {
let v = LineSpaceLabel()
let typography = CLSystemToken.typography(token: .tbm)
v.textColor = .text
v.config(typography)
v.numberOfLines = 3
introductionStackH.addArrangedSubview(v)
return v
}()
introductionLabelTopButton = {
let v = UIButton()
v.addTarget(self, action: #selector(tapIntroductionTop), for: .touchUpInside)
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.edges.equalTo(introductionLabel)
}
return v
}()
expendButton = {
let v = EPIconGhostButton(radius: .none, iconSize: .xs, iconCode: .iconFullimage)
v.addTarget(self, action: #selector(tapExpandButton), for: .touchUpInside)
introductionStackH.addArrangedSubview(v)
v.snp.makeConstraints { make in
make.size.equalTo(v.bgImageSize())
}
v.isHidden = true //
return v
}()
aiGeneratedLabel = {
let v = CLLabel()
v.textColor = .c.ctsn
v.font = .t.tbs
overlay.addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.trailing.equalToSuperview().offset(-24)
make.top.equalTo(introductionStackH.snp.bottom).offset(8)
}
return v
}()
}
private func setupAlbumTitlePart(){
albumTitleView = {
let v = UIView()
addSubview(v)
v.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(CGFloat.lrs)
make.trailing.equalToSuperview().offset(-CGFloat.lrs)
make.top.equalTo(imageFieldContainer.snp.bottom).offset(16)
make.bottom.equalToSuperview().offset(-24)
make.height.equalTo(32)
}
return v
}()
albumTitleLabel = {
let v = CLLabel()
v.font = .t.ttm
albumTitleView.addSubview(v)
v.snp.makeConstraints { make in
make.center.equalToSuperview()
}
return v
}()
do{
let left = {
let v = CLLine()
albumTitleView.addSubview(v)
v.snp.makeConstraints { make in
make.height.equalTo(1)
make.leading.equalToSuperview()
make.trailing.equalTo(albumTitleLabel.snp.leading).offset(-16)
make.centerY.equalTo(albumTitleLabel)
}
return v
}()
let right = {
let v = CLLine()
albumTitleView.addSubview(v)
v.snp.makeConstraints { make in
make.height.equalTo(1)
make.trailing.equalToSuperview()
make.leading.equalTo(albumTitleLabel.snp.trailing).offset(16)
make.centerY.equalTo(albumTitleLabel)
}
return v
}()
left.isHidden = false
right.isHidden = false
}
albumTitleLabel.text = "Album"
topRightTag.text = "Secret Admirer"
topRightTag.isHidden = true
}
private func testData(){
nameLabel.text = "Alice, 24"
likeAndCount.contentLabel.text = "1.2k"
do {
let tag = RoleTag()
tag.title = "Sensibility"
tag.style = .blurPurple
tagsStackH.addArrangedSubview(tag)
}
do {
let tag = RoleTag()
tag.title = "Romantic"
tag.style = .blurTheme
tagsStackH.addArrangedSubview(tag)
}
introductionLabel.text = "She is a new trainee teacher who has just graduated. You are the most rebellious student in the whole school. In order to prove her ability, she took the initiative to apply to be your class teacher. In the upcoming college entrance examination, you two…"
aiGeneratedLabel.text = "Content generated by AI"
imageView.image = UIImage.egpic
}
// MARK: - Public Methods
func config(_ card: MeetCard) {
data = card
//
if let imageUrl = card.imageUrl {
imageView.loadImage(imageUrl)
}
//
if data?.secretAdmirer ?? false{
topRightTag.isHidden = false
}else {
topRightTag.isHidden = true
}
//
let name = card.nickname ?? "Unknown"
let age = card.age != nil ? ", \(card.age!)" : ""
nameLabel.text = "\(name)\(age)"
//
let likeCount = card.likedCount ?? 0
likeAndCount.contentLabel.text = formatLikeCount(likeCount)
//
tagsStackH.arrangedSubviews.forEach { $0.removeFromSuperview() }
//
if let character = card.character, !character.isEmpty {
let tag = RoleTag()
tag.title = character
//tag.style = .blurTheme
tag.style = .default
tagsStackH.addArrangedSubview(tag)
}
//
if let tag = card.tag, !tag.isEmpty {
let tagView = RoleTag()
tagView.title = tag
//tagView.style = .blurPurple
tagView.style = .default
tagsStackH.addArrangedSubview(tagView)
}
//
introductionLabel.text = card.introduction ?? ""
updateExpandButtonVisibility() //
aiGeneratedLabel.text = "Content generated by AI"
}
private func formatLikeCount(_ count: Int) -> String {
if count >= 1000 {
return String(format: "%.1fk", Double(count) / 1000.0)
} else {
return "\(count)"
}
}
private func updateExpandButtonVisibility() {
guard let text = introductionLabel.text, !text.isEmpty else {
expendButton.isHidden = true
return
}
// 3
let maxWidth = introductionLabel.frame.width > 0 ? introductionLabel.frame.width : (UIScreen.main.bounds.width - 48) //
let maxSize = CGSize(width: maxWidth, height: CGFloat.greatestFiniteMagnitude)
// 3
let threeLineHeight = introductionLabel.font.lineHeight * 3 + introductionLabel.font.lineHeight * 2 // 3 + 2
//
let actualSize = text.boundingRect(
with: maxSize,
options: [.usesLineFragmentOrigin, .usesFontLeading],
attributes: [.font: introductionLabel.font!],
context: nil
)
// 3
let hideBrowseIntroduction = actualSize.height <= threeLineHeight
expendButton.isHidden = hideBrowseIntroduction
introductionLabelTopButton.isHidden = hideBrowseIntroduction
}
// layoutSubviews
override func layoutSubviews() {
super.layoutSubviews()
updateExpandButtonVisibility()
}
// MARK: - Action
@objc private func tapExpandButton(){
guard let introduction = data?.introduction else{return}
let vc = RoleIntroBrowseDialogController()
vc.introduction = introduction
vc.imageUrl = data?.imageUrl
vc.show()
}
@objc private func tapIntroductionTop(){
tapExpandButton()
}
}