// // SettingsPopupView.swift // RoderickRalph // // Created by Neoa on 2025/8/19. // import Foundation import UIKit // 在文件顶部 import 之后、class 之前加: protocol SettingsPopupViewDelegate: AnyObject { func settingsPopupViewDidClose(_ view: SettingsPopupView) } class SettingsPopupView: UIView { weak var delegate: SettingsPopupViewDelegate? // MARK: - UI Components private let backgroundView: UIView = { let view = UIView() view.backgroundColor = UIColor.black.withAlphaComponent(0.5) // Semi-transparent gray background view.translatesAutoresizingMaskIntoConstraints = false return view }() private let settingButton: UIButton = { let button = UIButton(type: .system) button.setBackgroundImage(UIImage(named: "pqan333"), for: .normal) button.setTitle("设置", for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 18) button.translatesAutoresizingMaskIntoConstraints = false return button }() private let iconBGView: UIImageView = { let iv = UIImageView() iv.image = UIImage(named: "pqan336") iv.contentMode = .scaleAspectFit iv.translatesAutoresizingMaskIntoConstraints = false return iv }() private let iconImageView: UIImageView = { let iv = UIImageView() iv.image = UIImage(named: "catlogos") iv.contentMode = .scaleAspectFit iv.layer.cornerRadius = 24 iv.clipsToBounds = true iv.translatesAutoresizingMaskIntoConstraints = false return iv }() private let nikNmeLeftLabel: UILabel = { let label = UILabel() label.text = "昵 称" label.font = UIFont.systemFont(ofSize: 12) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let nikNmeRightLabel: UILabel = { let label = UILabel() label.text = "XXXX" label.backgroundColor = .white label.font = UIFont.systemFont(ofSize: 12) label.textColor = UIColor(hexString:"#E28814") label.layer.cornerRadius = 4 label.clipsToBounds = true label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false return label }() private let roleIDLeftLabel: UILabel = { let label = UILabel() label.text = "角色ID" label.font = UIFont.systemFont(ofSize: 12) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let roleIDRightLabel: UILabel = { let label = UILabel() label.text = "XXXX" label.backgroundColor = .white label.font = UIFont.systemFont(ofSize: 12) label.textColor = UIColor(hexString:"#E28814") label.layer.cornerRadius = 4 label.clipsToBounds = true label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false return label }() private let closeButton: UIButton = { let button = UIButton(type: .custom) button.setImage(UIImage(named: "pqan334"), for: .normal) button.addTarget(self, action: #selector(closePopup), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false return button }() private let musicLeftLabel: UILabel = { let label = UILabel() label.text = "音乐" label.font = UIFont.systemFont(ofSize: 12) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let musicSwitch: UISwitch = { let switchControl = UISwitch() switchControl.isOn = false switchControl.translatesAutoresizingMaskIntoConstraints = false return switchControl }() private let soundLeftLabel: UILabel = { let label = UILabel() label.text = "音效" label.font = UIFont.systemFont(ofSize: 12) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let soundSwitch: UISwitch = { let switchControl = UISwitch() switchControl.isOn = false switchControl.translatesAutoresizingMaskIntoConstraints = false return switchControl }() private let registrationTimeLabel: UILabel = { let label = UILabel() label.text = "注册时间: 2025-05-26 17:58:48" label.font = UIFont.systemFont(ofSize: 10) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let softwareNameLabel: UILabel = { let label = UILabel() label.text = "青柠檬记账" label.font = UIFont.systemFont(ofSize: 10) label.textColor = .white label.translatesAutoresizingMaskIntoConstraints = false return label }() private let popupBackgroundImageView: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "pqan335") // Background image for the pop-up imageView.contentMode = .scaleToFill imageView.translatesAutoresizingMaskIntoConstraints = false return imageView }() // MARK: - Initialization init() { super.init(frame: .zero) setupUI() setupConstraints() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - UI Setup private func setupUI() { addSubview(backgroundView) backgroundView.isUserInteractionEnabled = true // 允许事件穿透 addSubview(popupBackgroundImageView) addSubview(settingButton) addSubview(iconBGView) addSubview(iconImageView) addSubview(nikNmeLeftLabel) addSubview(nikNmeRightLabel) addSubview(roleIDLeftLabel) addSubview(roleIDRightLabel) addSubview(musicLeftLabel) addSubview(soundLeftLabel) addSubview(musicSwitch) addSubview(soundSwitch) addSubview(closeButton) addSubview(registrationTimeLabel) addSubview(softwareNameLabel) // Prefill from saved user info (if available) let nickname = UserDefaults.standard.string(forKey: "nickname") ?? "XXXX" let roleID = UserDefaults.standard.string(forKey: "roleID") ?? "XXXX" let regTime = UserDefaults.standard.string(forKey: "registryTimeStr") ?? "--" nikNmeRightLabel.text = nickname roleIDRightLabel.text = roleID registrationTimeLabel.text = "注册时间: \(regTime)" // 显示已选择的渠道名(如果有),否则使用默认占位 if let savedChannel = UserDefaults.standard.string(forKey: "selectedChannelName"), !savedChannel.isEmpty { softwareNameLabel.text = savedChannel } let head = UserDefaults.standard.string(forKey: "headImgURL") setIcon(with: head) // 最后添加背景视图(确保它在最底层) // 添加背景点击手势 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleBackgroundTap)) backgroundView.addGestureRecognizer(tapGesture) } private func setupConstraints() { NSLayoutConstraint.activate([ // Background (Gray) for the outer area backgroundView.topAnchor.constraint(equalTo: topAnchor), backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor), backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor), backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor), // Popup background image popupBackgroundImageView.centerXAnchor.constraint(equalTo: centerXAnchor), popupBackgroundImageView.centerYAnchor.constraint(equalTo: centerYAnchor), popupBackgroundImageView.widthAnchor.constraint(equalToConstant: 333), popupBackgroundImageView.heightAnchor.constraint(equalToConstant: 215), // Close Button closeButton.topAnchor.constraint(equalTo: popupBackgroundImageView.topAnchor, constant: -12), closeButton.trailingAnchor.constraint(equalTo: popupBackgroundImageView.trailingAnchor, constant: 12), closeButton.widthAnchor.constraint(equalToConstant: 24), closeButton.heightAnchor.constraint(equalToConstant: 24), settingButton.topAnchor.constraint(equalTo: popupBackgroundImageView.topAnchor, constant: 10), settingButton.centerXAnchor.constraint(equalTo: popupBackgroundImageView.centerXAnchor, constant: 0), settingButton.widthAnchor.constraint(equalToConstant: 132), settingButton.heightAnchor.constraint(equalToConstant: 37), iconBGView.topAnchor.constraint(equalTo: settingButton.bottomAnchor, constant: 5), iconBGView.leadingAnchor.constraint(equalTo: popupBackgroundImageView.leadingAnchor, constant: 33), iconBGView.widthAnchor.constraint(equalToConstant: 58), iconBGView.heightAnchor.constraint(equalToConstant: 58), iconImageView.centerXAnchor.constraint(equalTo: iconBGView.centerXAnchor), iconImageView.centerYAnchor.constraint(equalTo: iconBGView.centerYAnchor), iconImageView.widthAnchor.constraint(equalToConstant: 48), iconImageView.heightAnchor.constraint(equalToConstant: 48), nikNmeRightLabel.trailingAnchor.constraint(equalTo: popupBackgroundImageView.trailingAnchor,constant: -35), nikNmeRightLabel.topAnchor.constraint(equalTo: settingButton.bottomAnchor,constant: 14), nikNmeRightLabel.widthAnchor.constraint(equalToConstant: 130), nikNmeRightLabel.heightAnchor.constraint(equalToConstant: 24), nikNmeLeftLabel.trailingAnchor.constraint(equalTo: nikNmeRightLabel.leadingAnchor,constant: -12), nikNmeLeftLabel.centerYAnchor.constraint(equalTo: nikNmeRightLabel.centerYAnchor,constant: 0), roleIDRightLabel.trailingAnchor.constraint(equalTo: nikNmeRightLabel.trailingAnchor,constant: 0), roleIDRightLabel.topAnchor.constraint(equalTo: nikNmeRightLabel.bottomAnchor,constant: 3), roleIDRightLabel.widthAnchor.constraint(equalToConstant: 130), roleIDRightLabel.heightAnchor.constraint(equalToConstant: 24), roleIDLeftLabel.trailingAnchor.constraint(equalTo: roleIDRightLabel.leadingAnchor,constant: -12), roleIDLeftLabel.centerYAnchor.constraint(equalTo: roleIDRightLabel.centerYAnchor,constant: 0), musicLeftLabel.leadingAnchor.constraint(equalTo: iconBGView.leadingAnchor,constant: 0), musicLeftLabel.topAnchor.constraint(equalTo: iconBGView.bottomAnchor,constant: 24), // Music Switch musicSwitch.centerYAnchor.constraint(equalTo: musicLeftLabel.centerYAnchor, constant: 0), musicSwitch.leadingAnchor.constraint(equalTo: musicLeftLabel.trailingAnchor, constant: 10), // Sound Switch soundSwitch.centerYAnchor.constraint(equalTo: musicSwitch.centerYAnchor), soundSwitch.trailingAnchor.constraint(equalTo: popupBackgroundImageView.trailingAnchor, constant: -28), soundLeftLabel.centerYAnchor.constraint(equalTo: musicLeftLabel.centerYAnchor,constant: 0), soundLeftLabel.trailingAnchor.constraint(equalTo: soundSwitch.trailingAnchor,constant: -60), // Registration Time Label registrationTimeLabel.leadingAnchor.constraint(equalTo: musicLeftLabel.leadingAnchor, constant: 0), registrationTimeLabel.topAnchor.constraint(equalTo: musicLeftLabel.bottomAnchor,constant: 22), softwareNameLabel.centerYAnchor.constraint(equalTo: registrationTimeLabel.centerYAnchor, constant: 0), softwareNameLabel.trailingAnchor.constraint(equalTo: soundSwitch.trailingAnchor,constant: 0), ]) } // MARK: - Actions @objc private func closePopup() { delegate?.settingsPopupViewDidClose(self) removeFromSuperview() } @objc private func handleBackgroundTap() { closePopup() } // MARK: - Avatar Loading private static let imageCache = NSCache() private func setIcon(with urlString: String?) { guard let s = urlString, !s.isEmpty, let url = URL(string: s) else { iconImageView.image = UIImage(named: "catlogos") return } if let cached = SettingsPopupView.imageCache.object(forKey: url as NSURL) { iconImageView.image = cached return } URLSession.shared.dataTask(with: url) { data, _, _ in guard let data = data, let img = UIImage(data: data) else { return } SettingsPopupView.imageCache.setObject(img, forKey: url as NSURL) DispatchQueue.main.async { [weak self] in self?.iconImageView.image = img } }.resume() } }