// // FS_DetailsVC.swift // Funny_sounds // // Created by 忆海16 on 2024/8/16. // import UIKit import SnapKit import AVFoundation import SDWebImage class FS_DetailsVC: RootVC { var backBtn = UIButton() var collectBtn = UIButton() var camearBtn = UIButton() var bgimageV = UIImageView() var conentView = UIView() var conentBgImageV = UIImageView() var contengImageV = UIImageView() var nameLabel = UILabel() var bottomView = UIView() var bottomImageV = UIImageView() var delayView = UIView() var delayLabel = BorderedLabel() var delayBtn = UIButton() var delayimageV = UIImageView() var countdown: CountdownTimer? lazy var collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.backgroundColor = .clear collectionView.showsVerticalScrollIndicator = true return collectionView }() var captureSession: AVCaptureSession! var previewLayer: AVCaptureVideoPreviewLayer! var arr: [AudioFile] = [] var model:AudioFile? var audioPlayer: AVPlayer? var playerItem: AVPlayerItem? let cellWidth: CGFloat = 92 let cellHeight: CGFloat = 92 let cellSpacing: CGFloat = 10 override func viewDidLoad() { super.viewDidLoad() // 初始化捕捉会话 captureSession = AVCaptureSession() captureSession.sessionPreset = .high // 获取设备的默认视频捕捉设备 (通常是后置摄像头) guard let camera = AVCaptureDevice.default(for: .video) else { print("无法访问摄像头") return } do { // 将摄像头作为输入设备添加到会话中 let input = try AVCaptureDeviceInput(device: camera) if captureSession.canAddInput(input) { captureSession.addInput(input) } else { print("无法添加输入设备") return } } catch { print("Error: \(error.localizedDescription)") return } // 创建一个预览层,用来展示相机捕捉到的内容 previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.videoGravity = .resizeAspectFill previewLayer.frame = view.layer.bounds view.layer.addSublayer(previewLayer) // 启动捕捉会话 captureSession.startRunning() // 添加点击手势识别器 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) bgimageV.isUserInteractionEnabled = true bgimageV.addGestureRecognizer(tapGesture) setUI() setcollectionView() setEditUI() let audioFile = AudioFile(title: model?.title ?? "", mp3Url: model?.mp3Url ?? "", preUrl: model?.preUrl ?? "") // 检查是否已收藏 if collectManager.shared.isFavorite(audioFile: audioFile) { print("音频文件已被收藏") self.collectBtn.isSelected = true } else { print("音频文件未被收藏") self.collectBtn.isSelected = false } preloadAudio() } // MARK: - Preload Audio func preloadAudio() { // MP3 file URL if let url = URL(string: model!.mp3Url) { // Create AVPlayerItem with the URL playerItem = AVPlayerItem(url: url) // Initialize AVPlayer with the preloaded AVPlayerItem audioPlayer = AVPlayer(playerItem: playerItem) } else { print("Invalid audio URL") } } // MARK: - UI func setUI(){ bgimageV.image = UIImage(named: "settingBg") bgimageV.contentMode = .scaleAspectFill self.view.addSubview(bgimageV) backBtn.setImage(UIImage(named: "back"), for: .normal) backBtn.addTarget(self, action: #selector(back), for: .touchUpInside) self.view.addSubview(backBtn) collectBtn.setImage(UIImage(named: "collect_n"), for: .normal) collectBtn.setImage(UIImage(named: "collect_s"), for: .selected) collectBtn.addTarget(self, action: #selector(collectTouch), for: .touchUpInside) self.view.addSubview(collectBtn) camearBtn.setImage(UIImage(named: "camear_n"), for: .normal) camearBtn.setImage(UIImage(named: "camear_s"), for: .selected) camearBtn.addTarget(self, action: #selector(camearBtnTouch), for: .touchUpInside) self.view.addSubview(camearBtn) conentView.backgroundColor = .clear self.view.addSubview(conentView) conentBgImageV.image = UIImage(named: "contentBg") conentBgImageV.contentMode = .scaleAspectFill self.conentView.addSubview(conentBgImageV) contengImageV.image = UIImage(named: "collectionImageV") contengImageV.layer.cornerRadius = 70 contengImageV.contentMode = .scaleToFill contengImageV.clipsToBounds = true self.conentView.addSubview(contengImageV) nameLabel.text = "Air Horn1" nameLabel.font = UIFont(name: "PaytoneOne-Regular", size: 25) nameLabel.textColor = .white nameLabel.numberOfLines = 0 nameLabel.textAlignment = .center self.conentView.addSubview(nameLabel) bottomView.backgroundColor = .clear self.view.addSubview(bottomView) bottomImageV.image = UIImage(named: "alphabgImageV") bottomImageV.contentMode = .scaleAspectFill self.bottomView.addSubview(bottomImageV) collectionView.backgroundColor = .clear collectionView.showsHorizontalScrollIndicator = false self.bottomView.addSubview(collectionView) delayView.backgroundColor = UIColor.hexSting(color: "#4EDB96", alpha: 0.8) delayView.layer.cornerRadius = 8 delayView.clipsToBounds = true self.view.addSubview(delayView) delayLabel.text = "Delay: OFF" delayLabel.font = UIFont(name: "PaytoneOne-Regular", size: 15) delayLabel.textColor = .white // 设置文本颜色为白色 delayLabel.numberOfLines = 0 delayLabel.textAlignment = .center // 设置阴影效果 let shadow = NSShadow() shadow.shadowColor = UIColor.black.withAlphaComponent(1.0) // 黑色阴影 shadow.shadowOffset = CGSize(width: 0, height: 6) // 向下偏移2个点 shadow.shadowBlurRadius = 0 // 无模糊度 // 设置属性字符串并应用阴影 let attributedText = NSMutableAttributedString(string: delayLabel.text!) attributedText.addAttribute(.shadow, value: shadow, range: NSRange(location: 0, length: delayLabel.text!.count)) delayLabel.attributedText = attributedText delayLabel.sizeToFit() self.delayView.addSubview(delayLabel) delayimageV.image = UIImage(named: "delayimageV") self.delayView.addSubview(delayimageV) delayBtn.addTarget(self, action: #selector(delaysTouch), for: .touchUpInside) self.delayView.addSubview(delayBtn) bgimageV.snp.makeConstraints { make in make.width.equalTo(self.view) make.height.equalTo(self.view) } backBtn.snp.makeConstraints { make in make.top.equalTo(self.view.safeAreaLayoutGuide).offset(20) make.height.width.equalTo(36) make.left.equalToSuperview().offset(20) } collectBtn.snp.makeConstraints { make in make.centerY.equalTo(backBtn) make.right.equalToSuperview().offset(-13) make.width.height.equalTo(48) } camearBtn.snp.makeConstraints { make in make.centerX.equalTo(collectBtn) make.top.equalTo(collectBtn.snp.bottom).offset(18) make.width.height.equalTo(48) } conentView.snp.makeConstraints { make in make.height.equalTo(260) make.width.equalTo(220) make.top.equalTo(backBtn.snp.bottom).offset(60) make.centerX.equalToSuperview() } conentBgImageV.snp.makeConstraints { make in make.width.height.equalTo(200) make.top.equalTo(conentView.snp.top) make.centerX.equalTo(conentView) } contengImageV.snp.makeConstraints { make in make.height.width.equalTo(140) make.centerX.centerY.equalTo(conentBgImageV) } nameLabel.snp.makeConstraints { make in make.top.equalTo(conentBgImageV.snp.bottom).offset(10) make.left.equalTo(conentView.snp.left).offset(5) make.right.equalTo(conentView.snp.right).offset(5) } bottomView.snp.makeConstraints { make in make.bottom.equalTo(self.view.safeAreaLayoutGuide).offset(0) make.height.equalTo(120) make.width.equalToSuperview() } bottomImageV.snp.makeConstraints { make in make.bottom.equalTo(self.view.safeAreaLayoutGuide).offset(0) make.height.equalTo(120) make.width.equalToSuperview() } collectionView.snp.makeConstraints { make in make.width.height.equalTo(bottomView) } delayView.snp.makeConstraints { make in make.width.equalToSuperview().offset(-40) make.height.equalTo(40) make.bottom.equalTo(collectionView.snp.top).offset(-60) make.centerX.equalToSuperview() } delayLabel.snp.makeConstraints { make in make.left.equalTo(delayView.snp.left).offset(16) make.centerY.equalTo(delayView).offset(-4) } delayimageV.snp.makeConstraints { make in make.centerY.equalTo(delayView) // make.width.equalTo(6) // make.height.equalTo(7) make.left.equalTo(delayLabel.snp.right).offset(15) } delayBtn.snp.makeConstraints { make in make.width.height.equalTo(delayView) } } // MARK: -collectionView func setcollectionView(){ let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal collectionView.delegate = self collectionView.dataSource = self collectionView.collectionViewLayout = layout collectionView.register(FS_DetailsCollectionViewCell.self, forCellWithReuseIdentifier: "FS_DetailsCollectionViewCell") } // MARK: - 修改UI func setEditUI(){ if let imageURL = URL(string: model?.preUrl ?? "") { contengImageV.sd_setImage(with: imageURL, placeholderImage: UIImage(named: "collectionImageV")) } self.nameLabel.text = model?.title } // MARK: - 返回 @objc func back(){ self.navigationController?.popViewController(animated: true) } // MARK: - 收藏点击 @objc func collectTouch(){ let audioFile = AudioFile(title: model?.title ?? "", mp3Url: model?.mp3Url ?? "", preUrl: model?.preUrl ?? "") collectManager.shared.toggleFavorite(audioFile: audioFile) // 检查是否已收藏 if collectManager.shared.isFavorite(audioFile: audioFile) { print("音频文件已被收藏") self.collectBtn.isSelected = true } else { print("音频文件未被收藏") self.collectBtn.isSelected = false } } // MARK: - 相机点击 @objc func camearBtnTouch(){ if self.camearBtn.isSelected == true{ self.camearBtn.isSelected = false self.conentView.isHidden = false self.bgimageV.isHidden = false }else{ self.camearBtn.isSelected = true self.camearBtn.isSelected = true self.conentView.isHidden = true self.bgimageV.isHidden = true } } // MARK: - 相机 override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // 确保预览层的大小在旋转或布局改变时更新 previewLayer.frame = view.layer.bounds } // MARK: - 全屏点击 @objc func handleTap() { // 点击时播放音频 playAudio() } // MARK: - 播放 func playAudio() { // MP3 文件的 URL // if let url = URL(string: model!.mp3Url) { // // 初始化 AVPlayer // audioPlayer = AVPlayer(url: url) // audioPlayer?.play() // } else { // print("无效的音频 URL") // } if let player = audioPlayer { player.seek(to: .zero) player.play() } else { print("Audio player is not ready") } } // MARK: - 点击选择倒计时 @objc func delaysTouch() { print("delaysTouch called") let pickerView = CustomPickerView() pickerView.onValueSelected = { value in print("Selected value: \(value)") // 停止旧的计时器(如果有的话) self.countdown?.stop() // 创建新的计时器实例 self.countdown = CountdownTimer(seconds: value, onTick: { remainingSeconds in print("剩余时间: \(remainingSeconds) 秒") // 在主线程上更新 UI DispatchQueue.main.async { self.delayLabel.text = "Delay: \(remainingSeconds) S" } }, onComplete: { print("倒计时结束!") // 在主线程上更新 UI 和播放音频 DispatchQueue.main.async { self.playAudio() self.delayLabel.text = "Delay: OFF" } }) // 在主线程上启动计时器 DispatchQueue.main.async { self.countdown?.start() } } pickerView.showInView(self.view) print("pickerView shown") } } // MARK: -设置collectionView代理 extension FS_DetailsVC:UICollectionViewDelegateFlowLayout,UICollectionViewDataSource,UICollectionViewDelegate{ func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return arr.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell{ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FS_DetailsCollectionViewCell", for: indexPath)as!FS_DetailsCollectionViewCell cell.model = arr[indexPath.row] return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: cellWidth, height: cellHeight) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { return cellSpacing } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: cellSpacing, bottom: 0, right: cellSpacing) } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){ self.model = arr[indexPath.row] setEditUI() preloadAudio() playAudio() } }