// // LaunchPrivacyConsentView.swift // QuickLocation // import UIKit final class LaunchPrivacyConsentView: UIView, UITextViewDelegate { var onAgree: (() -> Void)? var onDisagree: (() -> Void)? var onOpenURL: ((String) -> Void)? override init(frame: CGRect) { super.init(frame: frame) setupUI() configureBody() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func show(in host: UIView) { frame = host.bounds autoresizingMask = [.flexibleWidth, .flexibleHeight] host.addSubview(self) layoutIfNeeded() dimView.alpha = 0 card.transform = CGAffineTransform(translationX: 0, y: bounds.height * 0.4) UIView.animate(withDuration: 0.32, delay: 0, options: [.curveEaseOut]) { self.dimView.alpha = 1 self.card.transform = .identity } } private func setupUI() { addSubview(dimView) addSubview(card) card.addSubview(gradientView) card.addSubview(titleLab) card.addSubview(bodyTextView) card.addSubview(agreeBtn) card.addSubview(disagreeBtn) dimView.layoutChain.edges() card.layoutChain .edgesHorzontal() .bottom() gradientView.layoutChain .top() .edgesHorzontal() .height(120) titleLab.layoutChain .top(28) .edgesHorzontal(24) .height(28) bodyTextView.layoutChain .topToBottomOfView(titleLab, offset: 16) .edgesHorzontal(24) agreeBtn.layoutChain .topToBottomOfView(bodyTextView, offset: 22) .edgesHorzontal(30) .height(56) disagreeBtn.layoutChain .topToBottomOfView(agreeBtn, offset: 12) .centerX() .bottom(kSafeBottomMargin + 8) .height(24) agreeBtn.addTarget(self, action: #selector(handleAgree), for: .touchUpInside) disagreeBtn.addTarget(self, action: #selector(handleDisagree), for: .touchUpInside) } private func configureBody() { let full = """ 请你知悉,为保障为您正常提供相应服务,当您在未登录/未注册状态下进行浏览和搜索时,需要开启以下权限: 1.个人信息类型:设备信息(包括设备型号、设备标识符)。 2.位置权限(始终允许),您同意开启设备定位服务后,我们会通过GPS或WiFi等方式持续收集您的地理位置信息,将用于为您记录位置信息和为您的好友发送位置信息。您可以通过关闭手机定位服务,停止我们对您的地理位置信息进行收集,同时我们将对您的好友停止更新您的位置。 想了解更多服务协议、隐私内容和使用第三方SDK详情,请阅读我们的《用户服务协议》和《隐私政策》。 """ let paragraph = NSMutableParagraphStyle() paragraph.lineSpacing = 5 paragraph.paragraphSpacing = 8 let attributed = NSMutableAttributedString( string: full, attributes: [ .font: UIFont.systemFont(ofSize: 14, weight: .regular), .foregroundColor: UIColor(hexStr: "#333333"), .paragraphStyle: paragraph ] ) let agreementRange = (full as NSString).range(of: "《用户服务协议》") let privacyRange = (full as NSString).range(of: "《隐私政策》") if agreementRange.location != NSNotFound { attributed.addAttributes([ .foregroundColor: UIColor(hexStr: "#16B3FF"), .link: "UserAgreement" ], range: agreementRange) } if privacyRange.location != NSNotFound { attributed.addAttributes([ .foregroundColor: UIColor(hexStr: "#16B3FF"), .link: "PrivacyPolicy" ], range: privacyRange) } bodyTextView.attributedText = attributed bodyTextView.linkTextAttributes = [ .foregroundColor: UIColor(hexStr: "#16B3FF"), .underlineStyle: NSUnderlineStyle.single.rawValue ] bodyTextView.delegate = self } func textView( _ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction ) -> Bool { switch URL.absoluteString { case "UserAgreement": onOpenURL?(URLManager.shared.userAgreementUrl) case "PrivacyPolicy": onOpenURL?(URLManager.shared.privacyPolicyUrl) default: break } return false } func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { false } @objc private func handleAgree() { onAgree?() } @objc private func handleDisagree() { onDisagree?() } private lazy var dimView: UIView = { let view = UIView() view.backgroundColor = UIColor.black.withAlphaComponent(0.45) return view }() private lazy var card: UIView = { let view = UIView() view.backgroundColor = .white view.layer.cornerRadius = 28 view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] view.clipsToBounds = true return view }() private lazy var gradientView: LaunchPrivacyGradientView = { let view = LaunchPrivacyGradientView() view.isUserInteractionEnabled = false return view }() private lazy var titleLab: UILabel = { let label = UILabel() label.text = "服务协议及隐私政策" label.font = .systemFont(ofSize: 20, weight: .semibold) label.textColor = UIColor(hexStr: "#1A1A1A") label.textAlignment = .center return label }() private lazy var bodyTextView: UITextView = { let textView = UITextView() textView.backgroundColor = .clear textView.isEditable = false textView.isScrollEnabled = false textView.isSelectable = true textView.textContainerInset = .zero textView.textContainer.lineFragmentPadding = 0 return textView }() private lazy var agreeBtn: UIButton = { let btn = UIButton(type: .custom) btn.cornerRadius = 20 btn.setTitle("同意并进入", for: .normal) btn.setTitleColor(.white, for: .normal) btn.titleLabel?.font = FontManager.boboBold(18) btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal) return btn }() private lazy var disagreeBtn: UIButton = { let btn = UIButton(type: .system) btn.setTitle("不同意", for: .normal) btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal) btn.titleLabel?.font = .systemFont(ofSize: 15, weight: .regular) return btn }() } private final class LaunchPrivacyGradientView: UIView { override class var layerClass: AnyClass { CAGradientLayer.self } override func layoutSubviews() { super.layoutSubviews() guard let layer = layer as? CAGradientLayer else { return } layer.colors = [ UIColor(hexStr: "#D9F8F0").cgColor, UIColor.white.cgColor ] layer.startPoint = CGPoint(x: 0.5, y: 0) layer.endPoint = CGPoint(x: 0.5, y: 1) } }