LNLoginCaptchaInputViewController.swift 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 onCaptchaCoolDownChanged(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. func onUserLogin() {
  56. navigationController?.popToRootViewController(animated: true)
  57. }
  58. }
  59. extension LNLoginCaptchaInputViewController: UITextViewDelegate {
  60. func textView(_ textView: UITextView, shouldInteractWith URL: URL,
  61. in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
  62. showLoading()
  63. LNAccountManager.shared.getLoginCaptcha(code: code, phone: phone) { [weak self] success in
  64. dismissLoading()
  65. guard self != nil else { return }
  66. guard success else { return }
  67. showToast(.init(key: "B00030"))
  68. }
  69. return false
  70. }
  71. func textViewDidChangeSelection(_ textView: UITextView) {
  72. textView.selectedTextRange = nil
  73. }
  74. }
  75. extension LNLoginCaptchaInputViewController: LNCaptchaInputViewDelegate {
  76. func onCaptchaInputChange(view: LNCaptchaInputView) {
  77. guard view.hasDone else { return }
  78. LNAccountManager.shared.loginByPhone(code: code, num: phone, captcha: view.curInput)
  79. }
  80. }
  81. extension LNLoginCaptchaInputViewController {
  82. private func setupViews() {
  83. showNavigationBar = false
  84. let cover = UIImageView(image: .icLoginProfileBg)
  85. view.addSubview(cover)
  86. cover.snp.makeConstraints { make in
  87. make.top.horizontalEdges.equalToSuperview()
  88. }
  89. let fakeNav = LNFakeNaviBar()
  90. fakeNav.showBackButton()
  91. view.addSubview(fakeNav)
  92. fakeNav.snp.makeConstraints { make in
  93. make.horizontalEdges.equalToSuperview()
  94. make.top.equalToSuperview()
  95. }
  96. let textView = buildTextView()
  97. view.addSubview(textView)
  98. textView.snp.makeConstraints { make in
  99. make.horizontalEdges.equalToSuperview().inset(22)
  100. make.top.equalTo(fakeNav.snp.bottom).offset(20)
  101. }
  102. captchaInput.delegate = self
  103. view.addSubview(captchaInput)
  104. captchaInput.snp.makeConstraints { make in
  105. make.horizontalEdges.equalToSuperview().inset(22)
  106. make.top.equalTo(textView.snp.bottom).offset(24)
  107. make.height.equalTo(64)
  108. }
  109. let tipsView = buildCoolDown()
  110. view.addSubview(tipsView)
  111. tipsView.snp.makeConstraints { make in
  112. make.horizontalEdges.equalToSuperview().inset(22 - 4)
  113. make.top.equalTo(captchaInput.snp.bottom).offset(24 - 7) // 7 是 UITextView 自身的内容缩进
  114. }
  115. view.onTap { [weak self] in
  116. guard let self else { return }
  117. view.endEditing(true)
  118. }
  119. }
  120. private func buildTextView() -> UIView {
  121. let container = UIView()
  122. let titleLabel = UILabel()
  123. titleLabel.text = .init(key: "B00025")
  124. titleLabel.font = .heading_h1
  125. titleLabel.textColor = .text_5
  126. container.addSubview(titleLabel)
  127. titleLabel.snp.makeConstraints { make in
  128. make.horizontalEdges.equalToSuperview()
  129. make.top.equalToSuperview()
  130. }
  131. let descLabel = UILabel()
  132. descLabel.text = .init(key: "B00026") + "\n\(code) \(phone)"
  133. descLabel.font = .body_m
  134. descLabel.textColor = .text_4
  135. descLabel.numberOfLines = 0
  136. container.addSubview(descLabel)
  137. descLabel.snp.makeConstraints { make in
  138. make.horizontalEdges.equalToSuperview()
  139. make.top.equalTo(titleLabel.snp.bottom).offset(13)
  140. make.bottom.equalToSuperview()
  141. }
  142. return container
  143. }
  144. private func buildCoolDown() -> UIView {
  145. tipsView.font = .body_m
  146. tipsView.isEditable = false
  147. tipsView.delegate = self
  148. tipsView.showsVerticalScrollIndicator = false
  149. tipsView.showsHorizontalScrollIndicator = false
  150. tipsView.backgroundColor = .clear
  151. tipsView.linkTextAttributes = [.foregroundColor: UIColor.text_6]
  152. return tipsView
  153. }
  154. }