| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- //
- // SettingsPopupView.swift
- // RoderickRalph
- //
- // Created by Neoa on 2025/8/19.
- //
- import Foundation
- import UIKit
- // 在文件顶部 import 之后、class 之前加:
- protocol OverlayPanelAgent: AnyObject {
- func overlayPanelDidDismiss(_ panel: OverlayPanelView)
- }
- class OverlayPanelView: UIView {
- weak var delegate: OverlayPanelAgent?
-
- // MARK: - UI Components
- private let backdropView: UIView = {
- let view = UIView()
- view.backgroundColor = UIColor.black.withAlphaComponent(0.5) // Semi-transparent gray background
- view.translatesAutoresizingMaskIntoConstraints = false
- return view
- }()
-
- private let titleButton: UIButton = {
- let button = UIButton(type: .system)
- button.setBackgroundImage(UIImage(named: "res_x8brwne3"), 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 avatarFrameView: UIImageView = {
- let iv = UIImageView()
- iv.image = UIImage(named: "res_b8xhu2tz")
- iv.contentMode = .scaleAspectFit
- iv.translatesAutoresizingMaskIntoConstraints = false
- return iv
- }()
- private let avatarImageView: 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 nicknameLabel: UILabel = {
- let label = UILabel()
- label.text = "昵 称"
- label.font = UIFont.systemFont(ofSize: 12)
- label.textColor = .white
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
-
- private let nicknameValueLabel: 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 roleIdLabel: UILabel = {
- let label = UILabel()
- label.text = "角色ID"
- label.font = UIFont.systemFont(ofSize: 12)
- label.textColor = .white
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
-
- private let roleIdValueLabel: 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 dismissButton: UIButton = {
- let button = UIButton(type: .custom)
- button.setImage(UIImage(named: "res_9mx2yiyi"), for: .normal)
- button.addTarget(self, action: #selector(dismissPanel), for: .touchUpInside)
- button.translatesAutoresizingMaskIntoConstraints = false
- return button
- }()
- private let musicLabel: UILabel = {
- let label = UILabel()
- label.text = "音乐"
- label.font = UIFont.systemFont(ofSize: 12)
- label.textColor = .white
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
- private let musicToggle: UISwitch = {
- let switchControl = UISwitch()
- switchControl.isOn = false
- switchControl.translatesAutoresizingMaskIntoConstraints = false
- return switchControl
- }()
-
- private let sfxLabel: UILabel = {
- let label = UILabel()
- label.text = "音效"
- label.font = UIFont.systemFont(ofSize: 12)
- label.textColor = .white
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
- private let sfxToggle: UISwitch = {
- let switchControl = UISwitch()
- switchControl.isOn = false
- switchControl.translatesAutoresizingMaskIntoConstraints = false
- return switchControl
- }()
- private let registeredAtLabel: 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 appNameLabel: UILabel = {
- let label = UILabel()
- label.text = "青柠檬记账"
- label.font = UIFont.systemFont(ofSize: 10)
- label.textColor = .white
- label.translatesAutoresizingMaskIntoConstraints = false
- return label
- }()
- private let panelImageView: UIImageView = {
- let imageView = UIImageView()
- imageView.image = UIImage(named: "res_ew6zkg25") // Background image for the pop-up
- imageView.contentMode = .scaleToFill
- imageView.translatesAutoresizingMaskIntoConstraints = false
- return imageView
- }()
- // MARK: - Initialization
- init() {
- super.init(frame: .zero)
- buildInterface()
- applyConstraints()
- }
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- // MARK: - UI Setup
- private func buildInterface() {
-
- addSubview(backdropView)
- backdropView.isUserInteractionEnabled = true // 允许事件穿透
- addSubview(panelImageView)
-
- addSubview(titleButton)
- addSubview(avatarFrameView)
- addSubview(avatarImageView)
- addSubview(nicknameLabel)
- addSubview(nicknameValueLabel)
- addSubview(roleIdLabel)
- addSubview(roleIdValueLabel)
- addSubview(musicLabel)
- addSubview(sfxLabel)
- addSubview(musicToggle)
- addSubview(sfxToggle)
- addSubview(dismissButton)
- addSubview(registeredAtLabel)
- addSubview(appNameLabel)
- // 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") ?? "--"
- nicknameValueLabel.text = nickname
- roleIdValueLabel.text = roleID
- registeredAtLabel.text = "注册时间: \(regTime)"
- // 显示已选择的渠道名(如果有),否则使用默认占位
- if let savedChannel = UserDefaults.standard.string(forKey: "selectedChannelName"), !savedChannel.isEmpty {
- appNameLabel.text = savedChannel
- }
- let head = UserDefaults.standard.string(forKey: "headImgURL")
- assignAvatar(with: head)
- // 最后添加背景视图(确保它在最底层)
-
- // 添加背景点击手势
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(backdropTapped))
- backdropView.addGestureRecognizer(tapGesture)
- }
- private func applyConstraints() {
- NSLayoutConstraint.activate([
- // Background (Gray) for the outer area
- backdropView.topAnchor.constraint(equalTo: topAnchor),
- backdropView.bottomAnchor.constraint(equalTo: bottomAnchor),
- backdropView.leadingAnchor.constraint(equalTo: leadingAnchor),
- backdropView.trailingAnchor.constraint(equalTo: trailingAnchor),
-
- // Popup background image
- panelImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
- panelImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
- panelImageView.widthAnchor.constraint(equalToConstant: 333),
- panelImageView.heightAnchor.constraint(equalToConstant: 215),
-
- // Close Button
- dismissButton.topAnchor.constraint(equalTo: panelImageView.topAnchor, constant: -12),
- dismissButton.trailingAnchor.constraint(equalTo: panelImageView.trailingAnchor, constant: 12),
- dismissButton.widthAnchor.constraint(equalToConstant: 24),
- dismissButton.heightAnchor.constraint(equalToConstant: 24),
- titleButton.topAnchor.constraint(equalTo: panelImageView.topAnchor, constant: 10),
- titleButton.centerXAnchor.constraint(equalTo: panelImageView.centerXAnchor, constant: 0),
- titleButton.widthAnchor.constraint(equalToConstant: 132),
- titleButton.heightAnchor.constraint(equalToConstant: 37),
- avatarFrameView.topAnchor.constraint(equalTo: titleButton.bottomAnchor, constant: 5),
- avatarFrameView.leadingAnchor.constraint(equalTo: panelImageView.leadingAnchor, constant: 33),
- avatarFrameView.widthAnchor.constraint(equalToConstant: 58),
- avatarFrameView.heightAnchor.constraint(equalToConstant: 58),
- avatarImageView.centerXAnchor.constraint(equalTo: avatarFrameView.centerXAnchor),
- avatarImageView.centerYAnchor.constraint(equalTo: avatarFrameView.centerYAnchor),
- avatarImageView.widthAnchor.constraint(equalToConstant: 48),
- avatarImageView.heightAnchor.constraint(equalToConstant: 48),
-
- nicknameValueLabel.trailingAnchor.constraint(equalTo: panelImageView.trailingAnchor,constant: -35),
- nicknameValueLabel.topAnchor.constraint(equalTo: titleButton.bottomAnchor,constant: 14),
- nicknameValueLabel.widthAnchor.constraint(equalToConstant: 130),
- nicknameValueLabel.heightAnchor.constraint(equalToConstant: 24),
- nicknameLabel.trailingAnchor.constraint(equalTo: nicknameValueLabel.leadingAnchor,constant: -12),
- nicknameLabel.centerYAnchor.constraint(equalTo: nicknameValueLabel.centerYAnchor,constant: 0),
- roleIdValueLabel.trailingAnchor.constraint(equalTo: nicknameValueLabel.trailingAnchor,constant: 0),
- roleIdValueLabel.topAnchor.constraint(equalTo: nicknameValueLabel.bottomAnchor,constant: 3),
- roleIdValueLabel.widthAnchor.constraint(equalToConstant: 130),
- roleIdValueLabel.heightAnchor.constraint(equalToConstant: 24),
-
- roleIdLabel.trailingAnchor.constraint(equalTo: roleIdValueLabel.leadingAnchor,constant: -12),
- roleIdLabel.centerYAnchor.constraint(equalTo: roleIdValueLabel.centerYAnchor,constant: 0),
- musicLabel.leadingAnchor.constraint(equalTo: avatarFrameView.leadingAnchor,constant: 0),
- musicLabel.topAnchor.constraint(equalTo: avatarFrameView.bottomAnchor,constant: 24),
- // Music Switch
- musicToggle.centerYAnchor.constraint(equalTo: musicLabel.centerYAnchor, constant: 0),
- musicToggle.leadingAnchor.constraint(equalTo: musicLabel.trailingAnchor, constant: 10),
-
- // Sound Switch
- sfxToggle.centerYAnchor.constraint(equalTo: musicToggle.centerYAnchor),
- sfxToggle.trailingAnchor.constraint(equalTo: panelImageView.trailingAnchor, constant: -28),
-
- sfxLabel.centerYAnchor.constraint(equalTo: musicLabel.centerYAnchor,constant: 0),
- sfxLabel.trailingAnchor.constraint(equalTo: sfxToggle.trailingAnchor,constant: -60),
-
- // Registration Time Label
- registeredAtLabel.leadingAnchor.constraint(equalTo: musicLabel.leadingAnchor, constant: 0),
- registeredAtLabel.topAnchor.constraint(equalTo: musicLabel.bottomAnchor,constant: 22),
-
- appNameLabel.centerYAnchor.constraint(equalTo: registeredAtLabel.centerYAnchor, constant: 0),
- appNameLabel.trailingAnchor.constraint(equalTo: sfxToggle.trailingAnchor,constant: 0),
- ])
- }
- // MARK: - Actions
- @objc private func dismissPanel() {
- delegate?.overlayPanelDidDismiss(self)
- removeFromSuperview()
- }
-
- @objc private func backdropTapped() {
- dismissPanel()
- }
- // MARK: - Avatar Loading
- private static let avatarCache = NSCache<NSURL, UIImage>()
- private func assignAvatar(with urlString: String?) {
- guard let s = urlString, !s.isEmpty, let url = URL(string: s) else {
- avatarImageView.image = UIImage(named: "catlogos")
- return
- }
- if let cached = OverlayPanelView.avatarCache.object(forKey: url as NSURL) {
- avatarImageView.image = cached
- return
- }
- URLSession.shared.dataTask(with: url) { data, _, _ in
- guard let data = data, let img = UIImage(data: data) else { return }
- OverlayPanelView.avatarCache.setObject(img, forKey: url as NSURL)
- DispatchQueue.main.async { [weak self] in
- self?.avatarImageView.image = img
- }
- }.resume()
- }
- }
|