ConferencePasswordView.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //
  2. // ConferencePasswordView.swift
  3. // TUIRoomKit
  4. //
  5. // Created by janejntang on 2024/7/30.
  6. //
  7. import Foundation
  8. import Factory
  9. import RTCRoomEngine
  10. class ConferencePasswordView: UIView {
  11. var roomId: String?
  12. private let maxNumber = 32
  13. weak var viewModel: ConferenceMainViewModel?
  14. private let passwordPattern = "^[A-Za-z0-9~`!@#$%^&*()\\-_=+{}\\[\\]\\\\|;:'\",<.>\\/?]+$"
  15. let shieldingView: UIView = {
  16. let view = UIView()
  17. view.backgroundColor = UIColor(0x0F1014).withAlphaComponent(0.7)
  18. return view
  19. }()
  20. let contentView: UIView = {
  21. let view = UIView()
  22. view.backgroundColor = UIColor(0xFFFFFF)
  23. view.layer.cornerRadius = 10
  24. return view
  25. }()
  26. let titleLabel: UILabel = {
  27. let view = UILabel()
  28. view.text = .conferencePassword
  29. view.backgroundColor = .clear
  30. view.textColor = UIColor(0x0F1014)
  31. view.font = UIFont.systemFont(ofSize: 16, weight: .medium)
  32. view.textAlignment = .center
  33. return view
  34. }()
  35. lazy var textField: UITextField = {
  36. let view = UITextField(frame: .zero)
  37. view.backgroundColor = .clear
  38. view.placeholder = .pleaseEnterTheConferencePassword
  39. view.textColor = UIColor(0x2B2E38)
  40. view.tintColor = UIColor(0x2B2E38).withAlphaComponent(0.7)
  41. view.font = UIFont.systemFont(ofSize: 16, weight: .regular)
  42. view.keyboardType = .asciiCapable
  43. view.textAlignment = isRTL ? .right : .left
  44. view.layer.cornerRadius = 10
  45. view.layer.borderWidth = 1
  46. view.layer.borderColor = UIColor(0x1C66E5).cgColor
  47. view.delegate = self
  48. view.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
  49. view.leftViewMode = .always
  50. let deleteButton = UIButton(type: .system)
  51. deleteButton.frame = CGRect(x: 0, y: 0, width: 60, height: 30)
  52. deleteButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 20, bottom: 5, right: 20)
  53. deleteButton.setImage(UIImage(named: "room_cancel", in: tuiRoomKitBundle(), compatibleWith: nil), for: .normal)
  54. deleteButton.addTarget(self, action: #selector(deleteAction(sender:)), for: .touchUpInside)
  55. view.rightView = deleteButton
  56. view.rightViewMode = .whileEditing
  57. view.isSecureTextEntry = true
  58. return view
  59. }()
  60. let cancelButton: UIButton = {
  61. let button = UIButton()
  62. button.setTitle(.cancel, for: .normal)
  63. button.setTitleColor(UIColor(0x4F586B), for: .normal)
  64. button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .regular)
  65. button.layer.borderWidth = 0.5
  66. button.layer.borderColor = UIColor(0xD5E0F2).withAlphaComponent(0.5).cgColor
  67. return button
  68. }()
  69. let sureButton: UIButton = {
  70. let button = UIButton()
  71. button.setTitle(.join, for: .normal)
  72. button.setTitleColor(UIColor(0x1C66E5), for: .normal)
  73. button.setTitleColor(UIColor(0x1C66E5).withAlphaComponent(0.5), for: .disabled)
  74. button.layer.borderWidth = 0.5
  75. button.layer.borderColor = UIColor(0xD5E0F2).withAlphaComponent(0.5).cgColor
  76. return button
  77. }()
  78. private var isViewReady: Bool = false
  79. override func didMoveToWindow() {
  80. super.didMoveToWindow()
  81. guard !isViewReady else { return }
  82. isViewReady = true
  83. constructViewHierarchy()
  84. activateConstraints()
  85. bindInteraction()
  86. }
  87. private func constructViewHierarchy() {
  88. addSubview(shieldingView)
  89. addSubview(contentView)
  90. contentView.addSubview(titleLabel)
  91. contentView.addSubview(textField)
  92. contentView.addSubview(cancelButton)
  93. contentView.addSubview(sureButton)
  94. }
  95. private func activateConstraints() {
  96. shieldingView.snp.makeConstraints { make in
  97. make.edges.equalToSuperview()
  98. }
  99. contentView.snp.makeConstraints { make in
  100. make.center.equalToSuperview()
  101. make.width.equalTo(323.scale375())
  102. make.height.equalTo(180.scale375Height())
  103. }
  104. titleLabel.snp.makeConstraints { make in
  105. make.top.equalToSuperview().offset(24.scale375Height())
  106. make.centerX.equalToSuperview()
  107. }
  108. textField.snp.makeConstraints { make in
  109. make.height.equalTo(40.scale375Height())
  110. make.width.equalTo(298.scale375())
  111. make.centerX.equalToSuperview()
  112. make.top.equalTo(titleLabel.snp.bottom).offset(14.scale375Height())
  113. }
  114. cancelButton.snp.makeConstraints { make in
  115. make.width.equalToSuperview().multipliedBy(0.5)
  116. make.leading.equalToSuperview()
  117. make.height.equalTo(54.scale375Height())
  118. make.bottom.equalToSuperview()
  119. }
  120. sureButton.snp.makeConstraints { make in
  121. make.width.equalToSuperview().multipliedBy(0.5)
  122. make.trailing.equalToSuperview()
  123. make.height.equalTo(54.scale375Height())
  124. make.bottom.equalToSuperview()
  125. }
  126. }
  127. private func bindInteraction() {
  128. cancelButton.addTarget(self, action: #selector(cancelAction(sender:)), for: .touchUpInside)
  129. sureButton.addTarget(self, action: #selector(sureAction(sender:)), for: .touchUpInside)
  130. updateSureButton()
  131. }
  132. private func updateSureButton() {
  133. guard let text = textField.text else { return }
  134. sureButton.isEnabled = text.count > 0
  135. }
  136. @objc func cancelAction(sender: UIButton) {
  137. guard superview != nil else { return }
  138. removeFromSuperview()
  139. guard let roomId = roomId else { return }
  140. viewModel?.handleWrongPasswordFault(roomId: roomId)
  141. }
  142. @objc func sureAction(sender: UIButton) {
  143. guard superview != nil else { return }
  144. viewModel?.joinConferenceParams?.password = textField.text
  145. viewModel?.joinConference()
  146. }
  147. func hide() {
  148. self.isHidden = true
  149. textField.resignFirstResponder()
  150. }
  151. func show(roomId: String) {
  152. self.roomId = roomId
  153. self.isHidden = false
  154. }
  155. @objc func deleteAction(sender: UIButton) {
  156. textField.text = ""
  157. sureButton.isEnabled = false
  158. }
  159. override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  160. super.touchesBegan(touches, with: event)
  161. guard let touch = touches.first else { return }
  162. let point = touch.location(in: self)
  163. guard layer.contains(point) else { return }
  164. textField.resignFirstResponder()
  165. }
  166. deinit {
  167. debugPrint("deinit:\(self)")
  168. }
  169. @Injected(\.conferenceStore) private var store
  170. }
  171. extension ConferencePasswordView: UITextFieldDelegate {
  172. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  173. guard let text = textField.text else { return true }
  174. let newText = NSString(string: text).replacingCharacters(in: range, with: string)
  175. let isPasswordValid = newText.isEmpty || checkPasswordIsValid(newText)
  176. let isPasswordNumberFit = newText.count <= maxNumber
  177. guard isPasswordValid, isPasswordNumberFit else { return false }
  178. sureButton.isEnabled = !newText.isEmpty
  179. return true
  180. }
  181. private func checkPasswordIsValid(_ password: String) -> Bool {
  182. let regex = NSPredicate(format:"SELF MATCHES %@", passwordPattern)
  183. return regex.evaluate(with: password)
  184. }
  185. }
  186. private extension String {
  187. static let conferencePassword = localized("Conference password")
  188. static let join = localized("Join")
  189. static let cancel = localized("Cancel")
  190. static let pleaseEnterTheConferencePassword = localized("Please enter the password")
  191. }