LNLoginCaptchaInputViewController.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. //
  2. // LNLoginCaptchaInputViewController.swift
  3. // Gami
  4. //
  5. // Created by OneeChan on 2026/1/16.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. extension UIView {
  11. func pushToLoginCaptcha(code: String, phone: String) {
  12. let vc = LNLoginCaptchaInputViewController(code: code, phone: phone)
  13. navigationController?.pushViewController(vc, animated: true)
  14. }
  15. }
  16. class LNLoginCaptchaInputViewController: LNViewController {
  17. private let code: String
  18. private let phone: String
  19. private let captchaInput = LNCaptchaInputView()
  20. private let tipsView = LNAutoSizeTextView()
  21. init(code: String, phone: String) {
  22. self.code = code
  23. self.phone = phone
  24. super.init(nibName: nil, bundle: nil)
  25. }
  26. required init?(coder: NSCoder) {
  27. fatalError("init(coder:) has not been implemented")
  28. }
  29. override func viewDidLoad() {
  30. super.viewDidLoad()
  31. setupViews()
  32. LNEventDeliver.addObserver(self)
  33. }
  34. }
  35. extension LNLoginCaptchaInputViewController: LNAccountManagerNotify {
  36. func onLoginCaptchaCoolDownChanged(time: Int) {
  37. if time == 0 {
  38. let text = NSMutableAttributedString(string: .init(key: "B00028"), attributes: [
  39. .foregroundColor: UIColor.text_5
  40. ])
  41. let resend = NSMutableAttributedString(string: .init(key: "B00029"), attributes: [
  42. .font: UIFont.heading_h4,
  43. .link: "Gami:resend",
  44. ])
  45. text.append(.init(string: " "))
  46. text.append(resend)
  47. tipsView.attributedText = text
  48. } else {
  49. let text: String = .init(key: "B00027") + " (\(time)s)"
  50. tipsView.attributedText = .init(string: text, attributes: [
  51. .foregroundColor: UIColor.text_3
  52. ])
  53. }
  54. }
  55. }
  56. extension LNLoginCaptchaInputViewController: UITextViewDelegate {
  57. func textView(_ textView: UITextView, shouldInteractWith URL: URL,
  58. in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
  59. showLoading()
  60. LNAccountManager.shared.getLoginCaptcha(code: code, phone: phone) { [weak self] success in
  61. dismissLoading()
  62. guard self != nil else { return }
  63. guard success else { return }
  64. showToast(.init(key: "B00030"))
  65. }
  66. return false
  67. }
  68. func textViewDidChangeSelection(_ textView: UITextView) {
  69. textView.selectedTextRange = nil
  70. }
  71. }
  72. extension LNLoginCaptchaInputViewController: LNCaptchaInputViewDelegate {
  73. func onCaptchaInputChange(view: LNCaptchaInputView) {
  74. guard view.hasDone else { return }
  75. LNAccountManager.shared.loginByPhone(code: code, num: phone, captcha: view.curInput)
  76. }
  77. }
  78. extension LNLoginCaptchaInputViewController {
  79. private func setupViews() {
  80. navigationBarColor = .clear
  81. let cover = UIImageView(image: .icLoginProfileBg)
  82. view.addSubview(cover)
  83. cover.snp.makeConstraints { make in
  84. make.horizontalEdges.equalToSuperview()
  85. make.top.equalTo(fakeNaviBgView)
  86. }
  87. let textView = buildTextView()
  88. view.addSubview(textView)
  89. textView.snp.makeConstraints { make in
  90. make.horizontalEdges.equalToSuperview().inset(22)
  91. make.top.equalToSuperview().offset(20)
  92. }
  93. captchaInput.delegate = self
  94. captchaInput.startInput()
  95. view.addSubview(captchaInput)
  96. captchaInput.snp.makeConstraints { make in
  97. make.horizontalEdges.equalToSuperview().inset(22)
  98. make.top.equalTo(textView.snp.bottom).offset(24)
  99. make.height.equalTo(64)
  100. }
  101. let tipsView = buildCoolDown()
  102. view.addSubview(tipsView)
  103. tipsView.snp.makeConstraints { make in
  104. make.horizontalEdges.equalToSuperview().inset(22 - 4)
  105. make.top.equalTo(captchaInput.snp.bottom).offset(24 - 7) // 7 是 UITextView 自身的内容缩进
  106. }
  107. view.onTap { [weak self] in
  108. guard let self else { return }
  109. view.endEditing(true)
  110. }
  111. }
  112. private func buildTextView() -> UIView {
  113. let container = UIView()
  114. let titleLabel = UILabel()
  115. titleLabel.text = .init(key: "B00025")
  116. titleLabel.font = .heading_h1
  117. titleLabel.textColor = .text_5
  118. container.addSubview(titleLabel)
  119. titleLabel.snp.makeConstraints { make in
  120. make.horizontalEdges.equalToSuperview()
  121. make.top.equalToSuperview()
  122. }
  123. let descLabel = UILabel()
  124. descLabel.text = .init(key: "B00026") + "\n\(code) \(phone)"
  125. descLabel.font = .body_m
  126. descLabel.textColor = .text_4
  127. descLabel.numberOfLines = 0
  128. container.addSubview(descLabel)
  129. descLabel.snp.makeConstraints { make in
  130. make.horizontalEdges.equalToSuperview()
  131. make.top.equalTo(titleLabel.snp.bottom).offset(13)
  132. make.bottom.equalToSuperview()
  133. }
  134. return container
  135. }
  136. private func buildCoolDown() -> UIView {
  137. tipsView.font = .body_m
  138. tipsView.isEditable = false
  139. tipsView.delegate = self
  140. tipsView.showsVerticalScrollIndicator = false
  141. tipsView.showsHorizontalScrollIndicator = false
  142. tipsView.backgroundColor = .clear
  143. tipsView.linkTextAttributes = [.foregroundColor: UIColor.text_6]
  144. return tipsView
  145. }
  146. }