KMVerificationCodeView.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. //
  2. // KMVerificationCodeView.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2023/2/23.
  6. //
  7. import Cocoa
  8. typealias KMVerificationCodeViewCancelAction = (_ view: KMVerificationCodeView) -> Void
  9. typealias KMVerificationCodeViewVerificationCodeAction = (_ view: KMVerificationCodeView, _ data: KMRegisterModel, _ codeString: String) -> Void
  10. typealias KMVerificationCodeViewDoneAction = (_ view: KMVerificationCodeView, _ data: KMRegisterModel, _ sender: NSButton) -> Void
  11. typealias KMVerificationCodeViewCloseAction = (_ view: KMVerificationCodeView) -> Void
  12. typealias KMVerificationCodeViewReSendAction = (_ view: KMVerificationCodeView, _ sender: NSTextView) -> Void
  13. class KMVerificationCodeView: KMBaseXibView {
  14. @IBOutlet weak var titleLabel: NSTextField!
  15. @IBOutlet weak var describeLabel: NSTextField!
  16. @IBOutlet var timerTextView: NSTextView!
  17. @IBOutlet weak var cancellationButton: NSButton!
  18. @IBOutlet weak var cancelButton: NSButton!
  19. @IBOutlet weak var closeButton: NSButton!
  20. @IBOutlet weak var textFieldContentView: NSView!
  21. @IBOutlet weak var code1ContentView: NSView!
  22. @IBOutlet weak var code1TextField: KMBaseTextField!
  23. @IBOutlet weak var code2ContentView: NSView!
  24. @IBOutlet weak var code2TextField: KMBaseTextField!
  25. @IBOutlet weak var code3ContentView: NSView!
  26. @IBOutlet weak var code3TextField: KMBaseTextField!
  27. @IBOutlet weak var code4ContentView: NSView!
  28. @IBOutlet weak var code4TextField: KMBaseTextField!
  29. @IBOutlet weak var code5ContentView: NSView!
  30. @IBOutlet weak var code5TextField: KMBaseTextField!
  31. @IBOutlet weak var code6ContentView: NSView!
  32. @IBOutlet weak var code6TextField: KMBaseTextField!
  33. @IBOutlet weak var doneButtonTopConstraint: NSLayoutConstraint!
  34. @IBOutlet weak var alertView: KMLightMemberAlertView!
  35. @IBOutlet weak var alertHeightConstraint: NSLayoutConstraint!
  36. @IBOutlet weak var closeBox: KMBox!
  37. var cancellationButtonVC: KMDesignButton!
  38. var cancelButtonVC: KMDesignButton!
  39. var cancelAction: KMVerificationCodeViewCancelAction?
  40. var doneAction: KMVerificationCodeViewDoneAction?
  41. var closeAction: KMVerificationCodeViewCloseAction?
  42. var reSendAction: KMVerificationCodeViewReSendAction?
  43. var verificationCodeAction: KMVerificationCodeViewVerificationCodeAction?
  44. var timer: Timer?
  45. var time: Int = -1
  46. let startTime = 60
  47. //验证码
  48. var verificationCode: String {
  49. get {
  50. return self.code1TextField.stringValue + self.code2TextField.stringValue + self.code3TextField.stringValue + self.code4TextField.stringValue + self.code5TextField.stringValue + self.code6TextField.stringValue
  51. }
  52. }
  53. var verificationCodeState: KMRequestServerErrorCodeType = .unknown
  54. var inputType: KMRegisterLogType = .login {
  55. didSet {
  56. switch self.inputType {
  57. case .register:
  58. self.verifyCodeType = .register
  59. case .loginInputPassword:
  60. self.verifyCodeType = .resetPassword
  61. case .accountInfo:
  62. self.verifyCodeType = .logOff
  63. default:
  64. print("")
  65. }
  66. self.cleanVerificationCode()
  67. self.reloadData()
  68. self.updateLanguage()
  69. }
  70. }
  71. var verifyCodeType: KMVerifyCodeType = .unknown {
  72. didSet {
  73. self.reloadData()
  74. self.updateLanguage()
  75. }
  76. }
  77. var isNetworking: Bool = false //是否正在进行网络请求
  78. var codeIsTrue: Bool = false //验证码是否正确
  79. var model: KMRegisterModel = KMRegisterModel()
  80. override func draw(_ dirtyRect: NSRect) {
  81. super.draw(dirtyRect)
  82. // Drawing code here.
  83. }
  84. override func setup() {
  85. super.setup()
  86. self.backgroundColor(NSColor(hex: "#FFFFFF"))
  87. self.titleLabel.font = NSFont.SFProTextSemibold(20.0)
  88. self.titleLabel.textColor = NSColor(hex: "#252629")
  89. self.describeLabel.font = NSFont.SFProTextRegular(14.0)
  90. self.describeLabel.textColor = NSColor(hex: "#252629")
  91. self.timerTextView.delegate = self
  92. self.timerTextView.frame = (self.timerTextView.enclosingScrollView?.contentView.bounds)!
  93. self.timerTextView.autoresizingMask = [.width, .height]
  94. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  95. for i in 0...textFieldArray.count - 1 {
  96. let textField = textFieldArray[i]
  97. if textField != nil {
  98. textField!.textField.textColor = NSColor(hex: "#252629")
  99. textField!.textField.font = NSFont.SFProTextSemibold(20.0)
  100. textField?.maxLen = 1
  101. textField?.model.isCanNull = true
  102. textField?.textField.tag = i + 10
  103. textField!.textField.alignment = .center
  104. textField?.superview?.border(NSColor(hex: "#DFE1E5"), 1, 2)
  105. textField?.textField.onFocus = { [unowned self] in
  106. self.cancelAllTextFieldFouce()
  107. textField?.superview?.border(NSColor(hex: "#1770F4"), 1, 2)
  108. }
  109. textField?.textDidEndEditing = { [unowned self] string in
  110. textField?.superview?.border(NSColor(hex: "#DFE1E5"), 1, 2)
  111. }
  112. textField?.textDidChange = { [unowned self] string in
  113. //自动验证验证码
  114. self.autoVerificationCode()
  115. var isNext = true
  116. if string == "" {
  117. isNext = false
  118. }
  119. for item in textFieldArray {
  120. let t = textField?.textField
  121. var tag = t!.tag + 1
  122. if !isNext {
  123. tag = t!.tag - 1
  124. }
  125. tag = max(10, tag)
  126. if item?.textField.tag == tag {
  127. item?.textField.becomeFirstResponder()
  128. item?.superview?.border(NSColor(hex: "#1770F4"), 1, 2)
  129. break
  130. }
  131. }
  132. }
  133. textField?.textDeleteAction = { [unowned self] string in
  134. if string == "" {
  135. for item in textFieldArray {
  136. let t = textField?.textField
  137. let tag = max(10, t!.tag - 1)
  138. if item?.textField.tag == tag {
  139. item?.textField.becomeFirstResponder()
  140. item?.superview?.border(NSColor(hex: "#1770F4"), 1, 2)
  141. break
  142. }
  143. }
  144. }
  145. }
  146. }
  147. }
  148. self.cancellationButtonVC = KMDesignButton(withType: .Text)
  149. self.cancellationButton.addSubview(self.cancellationButtonVC.view)
  150. self.cancellationButtonVC?.view.frame = self.cancellationButton.bounds
  151. self.cancellationButtonVC.target = self
  152. self.cancellationButtonVC.action = #selector(doneButtonAction)
  153. self.cancellationButtonVC.button(type: .Cta, size: .m)
  154. self.cancellationButtonVC.button.keyEquivalent = KMKeyEquivalent.enter
  155. self.cancelButtonVC = KMDesignButton(withType: .Text)
  156. self.cancelButton.addSubview(self.cancelButtonVC.view)
  157. self.cancelButtonVC?.view.frame = self.cancelButton.bounds
  158. self.cancelButtonVC.target = self
  159. self.cancelButtonVC.action = #selector(cancelButtonAction)
  160. self.cancelButtonVC.button(type: .Sec, size: .m)
  161. self.cancelButtonVC.button.keyEquivalent = KMKeyEquivalent.enter
  162. self.closeBox.moveCallback = { [unowned self] (mouseEntered, mouseBox) in
  163. if mouseEntered {
  164. self.closeButton.image = NSImage(named: "control_btn_icon_close_hov")
  165. } else {
  166. self.closeButton.image = NSImage(named: "control_btn_icon_close")
  167. }
  168. }
  169. }
  170. override func reloadData() {
  171. super.reloadData()
  172. if inputType == .accountInfo {
  173. self.closeButton.isHidden = false
  174. self.cancelButtonVC.button(type: .Sec, size: .m)
  175. self.cancelButtonVC.updateUI()
  176. } else {
  177. self.closeButton.isHidden = true
  178. self.cancelButtonVC.button(type: .Text, size: .m)
  179. self.cancelButtonVC.updateUI()
  180. }
  181. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  182. for item in textFieldArray {
  183. item?.isEnabled = !self.isNetworking
  184. }
  185. if self.verificationCode.count == 6 &&
  186. // self.time != -1 &&
  187. self.codeIsTrue {
  188. self.cancellationButtonVC.enabled = true
  189. } else {
  190. self.cancellationButtonVC.enabled = false
  191. self.showAlert(result: Result(code: 0))
  192. }
  193. }
  194. override func updateLanguage() {
  195. super.updateLanguage()
  196. if self.verifyCodeType == .unknown {
  197. self.titleLabel.stringValue = ""
  198. } else if self.verifyCodeType == .register {
  199. self.titleLabel.stringValue = NSLocalizedString("Sign Up", comment: "")
  200. } else if self.verifyCodeType == .logOff {
  201. self.titleLabel.stringValue = NSLocalizedString("Cancel Account", comment: "")
  202. } else if self.verifyCodeType == .resetPassword {
  203. self.titleLabel.stringValue = NSLocalizedString("Reset Password", comment: "")
  204. }
  205. self.describeLabel.stringValue = NSLocalizedString("Enter the verification code", comment: "")
  206. if inputType == .unknown {
  207. self.cancelButtonVC.stringValue = ""
  208. } else if inputType == .accountInfo {
  209. self.cancelButtonVC.stringValue = NSLocalizedString("Cancel", comment: "")
  210. } else {
  211. self.cancelButtonVC.stringValue = NSLocalizedString("Back to previous step", comment: "")
  212. }
  213. if self.verifyCodeType == .unknown {
  214. self.cancellationButtonVC.stringValue = ""
  215. } else if self.verifyCodeType == .register {
  216. self.cancellationButtonVC.stringValue = NSLocalizedString("Sign Up", comment: "")
  217. } else if self.verifyCodeType == .logOff {
  218. self.cancellationButtonVC.stringValue = NSLocalizedString("Cancellation", comment: "")
  219. } else if self.verifyCodeType == .resetPassword {
  220. self.cancellationButtonVC.stringValue = NSLocalizedString("Next Step", comment: "")
  221. }
  222. let tempTime: String = String(self.time)
  223. var timeString = "(" + tempTime + NSLocalizedString("s", comment: "") + ")"
  224. if tempTime == "60" {
  225. timeString = NSLocalizedString("Click to resend", comment: "")
  226. } else if tempTime == "-1" {
  227. timeString = " "
  228. }
  229. //singin
  230. let string = NSLocalizedString("Didn't receive the verification code?", comment: "") + " " + timeString
  231. let attributedString = NSMutableAttributedString.init(string: string)
  232. let paragraphStyle = NSMutableParagraphStyle()
  233. paragraphStyle.alignment = .left;
  234. attributedString.addAttributes([NSAttributedString.Key.font : NSFont.SFProTextRegular(12.0),
  235. NSAttributedString.Key.foregroundColor : NSColor(hex: "#252629"),
  236. NSAttributedString.Key.paragraphStyle : paragraphStyle],
  237. range: NSRange(location: 0, length: string.count))
  238. let range = string.range(of: NSLocalizedString(timeString, comment: ""))
  239. attributedString.setAttributes([NSAttributedString.Key.font : NSFont.SFProTextRegular(12.0),
  240. NSAttributedString.Key.foregroundColor : NSColor(hex: "#1770F4"),
  241. NSAttributedString.Key.underlineColor : NSColor.clear,
  242. NSAttributedString.Key.link : "timer://"],
  243. range: string.nsRange(from: range!)!)
  244. self.timerTextView.textStorage?.setAttributedString(attributedString)
  245. }
  246. func cleanVerificationCode() {
  247. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  248. for item in textFieldArray {
  249. item?.stringValue = ""
  250. item?.textField.resignFirstResponder()
  251. if item != self.code1TextField {
  252. item?.superview?.border(NSColor(hex: "#DFE1E5"), 1, 2)
  253. }
  254. }
  255. self.model.verifyCode = ""
  256. }
  257. //验证码请求完成
  258. func updateNetworkingState(complete: Bool, codeIsTure: Bool) {
  259. self.isNetworking = !complete
  260. self.codeIsTrue = codeIsTure
  261. self.reloadData()
  262. if !codeIsTure {
  263. self.code6TextField.textField.becomeFirstResponder()
  264. }
  265. }
  266. //自动验证验证码
  267. func autoVerificationCode() {
  268. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  269. for item in textFieldArray {
  270. item?.textField.resignFirstResponder()
  271. }
  272. if self.verificationCode.count == 6 {
  273. if self.verificationCodeAction != nil {
  274. self.isNetworking = true
  275. self.model.verifyCode = self.verificationCode
  276. self.verificationCodeAction!(self, self.model, self.verificationCode)
  277. }
  278. }
  279. }
  280. }
  281. protocol KMVerificationCodeViewTimer {}
  282. extension KMVerificationCodeView: KMVerificationCodeViewTimer {
  283. func cleanTimer() {
  284. self.time = startTime
  285. self.updateLanguage()
  286. }
  287. func resetTimer() {
  288. self.time = startTime
  289. self.beginTimer()
  290. self.updateTimerData(timer: self.timer!)
  291. }
  292. func beginTimer() {
  293. if self.timer != nil {
  294. self.endTimer()
  295. }
  296. if self.time == -1 {
  297. self.time = startTime
  298. }
  299. self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateTimerData), userInfo: nil, repeats: true)
  300. }
  301. func endTimer() {
  302. self.timer?.invalidate()
  303. self.timer = nil
  304. self.updateLanguage()
  305. }
  306. @objc func updateTimerData(timer: Timer) {
  307. self.time -= 1
  308. if self.time == 0 {
  309. self.endTimer()
  310. self.time = startTime
  311. }
  312. self.updateLanguage()
  313. }
  314. }
  315. protocol KMVerificationCodeViewAction {}
  316. extension KMVerificationCodeView: KMVerificationCodeViewAction {
  317. func sendVerificationCode() {
  318. guard let callBack = reSendAction else { return }
  319. self.timerTextView.isSelectable = false
  320. callBack(self, self.timerTextView)
  321. }
  322. @IBAction func cancelButtonAction(_ sender: NSButton) {
  323. self.endTimer()
  324. guard let callBack = cancelAction else { return }
  325. callBack(self)
  326. }
  327. @IBAction func doneButtonAction(_ sender: NSButton) {
  328. guard let callBack = doneAction else { return }
  329. self.model.verifyCode = self.verificationCode
  330. self.changeDoneButtonState(enable: false)
  331. callBack(self, self.model, sender)
  332. }
  333. @IBAction func closeButtonAction(_ sender: Any) {
  334. guard let callBack = closeAction else { return }
  335. self.endTimer()
  336. callBack(self)
  337. }
  338. func showAlert(result: Result?) {
  339. if result != nil {
  340. self.alertView.result = result!
  341. if result?.code != 0 && result?.code != 200 {
  342. self.textFieldAlert()
  343. }
  344. }
  345. }
  346. func changeDoneButtonState(enable: Bool) {
  347. self.cancellationButtonVC.enabled = enable
  348. }
  349. func cancelAllTextFieldFouce() {
  350. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  351. for item in textFieldArray {
  352. item?.superview?.border(NSColor(hex: "#DFE1E5"), 1, 2)
  353. }
  354. }
  355. func textFieldAlert() {
  356. let textFieldArray = [self.code1TextField,self.code2TextField,self.code3TextField,self.code4TextField,self.code5TextField,self.code6TextField]
  357. for item in textFieldArray {
  358. item?.superview?.border(NSColor.red, 1, 2)
  359. }
  360. }
  361. }
  362. extension KMVerificationCodeView: NSTextViewDelegate {
  363. func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool {
  364. if link as! String == "timer://" && self.time == 60 {
  365. guard let callBack = reSendAction else { return true }
  366. textView.isSelectable = false
  367. callBack(self, textView)
  368. }
  369. return true
  370. }
  371. }
  372. extension KMVerificationCodeView: NSTextFieldDelegate {
  373. func controlTextDidEndEditing(_ obj: Notification) {
  374. print("controlTextDidEndEditing")
  375. let textField = obj.object as? NSTextField
  376. for view in self.textFieldContentView.subviews {
  377. let t = view.subviews.first as? FocusAwareTextField
  378. if t == textField {
  379. view.border(NSColor(hex: "#DFE1E5"), 1, 4)
  380. }
  381. }
  382. }
  383. }