// // LNSkillEditViewController.swift // Gami // // Created by OneeChan on 2026/1/25. // import Foundation import UIKit import SnapKit import Combine extension UIView { func pushToSkillEdit(_ info: LNSkillEditFieldsResponse) { showLoading() LNGameMateManager.shared.getJoinGameMateInfo { [weak self] res in dismissLoading() guard let self else { return } if res?.underReview == true { let vc = LNSkillReviewViewController() navigationController?.pushViewController(vc, animated: true) return } let vc = LNSkillEditViewController(info: info) navigationController?.pushViewController(vc, animated: true) } } } class LNSkillEditViewController: LNViewController { private let scrollView = UIScrollView() private let info: LNSkillEditFieldsResponse private let editPanel = LNSkillFieldsEditView() private let confirmButton = UIButton() init(info: LNSkillEditFieldsResponse) { self.info = info super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() setupViews() checkConfirmButton() } } extension LNSkillEditViewController { private func commit() { guard editPanel.checkAvailable else { return } showLoading() DispatchQueue.global().async { [weak self] in guard let self else { dismissLoading() return } let voices = info.fields.filter({ $0.type == .voice }) let group = DispatchGroup() var uploadDone = true for voice in voices { if let path = voice.value as? String, !path.starts(with: "http") { group.enter() LNFileUploader.shared.startUpload(type: .voice, fileURL: URL(fileURLWithPath: path), progressHandler: nil) { url, err in if let err { showToast(err) uploadDone = false } else if let url { voice.value = url } else { uploadDone = false } group.leave() } } } group.wait() if !uploadDone { dismissLoading() return } let input = LNEditSkillFieldsInfo() input.skillId = info.skillId input.apply = editPanel.needReview for item in info.fields { let config = LNCreateSkillFieldInfo() config.fieldCode = item.fieldCode config.value = item.value if item.type == .voice { config.duration = item.duration } input.fields.append(config) } LNGameMateManager.shared.commitSkillEdit(info: input) { [weak self] success in dismissLoading() guard let self else { return } guard success else { return } if input.apply { view.pushToSkillReview(cls: LNSkillCreateViewController.self) } else { navigationController?.popViewController(animated: true) } } } } } extension LNSkillEditViewController: LNSkillFieldBaseEditViewDelegate { func onSkillFieldBaseEditViewInputChanged(view: LNSkillFieldBaseEditView) { checkConfirmButton() } } extension LNSkillEditViewController { private func checkConfirmButton() { let allInput = editPanel.hasAllInput if allInput != confirmButton.isEnabled { confirmButton.isEnabled = allInput confirmButton.setBackgroundImage(allInput ? .primary_8 : nil, for: .normal) } } private func setupViews() { title = .init(key: "B00093") view.backgroundColor = .primary_1 view.onTap { [weak self] in guard let self else { return } view.endEditing(true) } scrollView.showsHorizontalScrollIndicator = false scrollView.showsVerticalScrollIndicator = false scrollView.contentInset = .init(top: 12, left: 0, bottom: -view.commonBottomInset + 32, right: 0) scrollView.adjustKeyoard() view.addSubview(scrollView) scrollView.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.top.equalToSuperview() make.bottom.equalToSuperview() } scrollView.addSubview(editPanel) editPanel.snp.makeConstraints { make in make.edges.equalToSuperview() make.width.equalToSuperview() } editPanel.delegate = self editPanel.update(info.bizCategoryName, fields: info.fields) let bottomMenu = UIView() view.addSubview(bottomMenu) bottomMenu.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.bottom.equalToSuperview() } let bottomGradient = CAGradientLayer() bottomGradient.colors = [ UIColor.white.withAlphaComponent(0).cgColor, UIColor.white.cgColor, UIColor.white.cgColor ] bottomGradient.locations = [0, 0.5, 1] bottomGradient.startPoint = .init(x: 0, y: 0) bottomGradient.endPoint = .init(x: 0, y: 1) bottomMenu.layer.addSublayer(bottomGradient) bottomMenu.publisher(for: \.bounds).removeDuplicates().sink { [weak bottomGradient] newValue in guard let bottomGradient else { return } bottomGradient.frame = newValue }.store(in: &cancellables) confirmButton.setTitle(.init(key: "A00002"), for: .normal) confirmButton.setTitleColor(.text_1, for: .normal) confirmButton.titleLabel?.font = .heading_h3 confirmButton.layer.cornerRadius = 23.5 confirmButton.backgroundColor = .fill_4 confirmButton.clipsToBounds = true confirmButton.isEnabled = false confirmButton.addAction(UIAction(handler: { [weak self] _ in guard let self else { return } commit() }), for: .touchUpInside) bottomMenu.addSubview(confirmButton) confirmButton.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(16) make.bottom.equalToSuperview().offset(view.commonBottomInset) make.top.equalToSuperview() make.height.equalTo(47) } } }