KMSignUpView.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // KMSignUpView.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by wanjun on 2024/10/23.
  6. //
  7. import Cocoa
  8. import Combine
  9. class KMSignUpView: KMBaseXibView {
  10. @IBOutlet weak var signUpLabel: NSTextField!
  11. @IBOutlet weak var loginModeBox: NSBox!
  12. @IBOutlet weak var verificationCodeButton: NSButton!
  13. @IBOutlet weak var selectBox1: NSBox!
  14. @IBOutlet weak var passwordButton: NSButton!
  15. @IBOutlet weak var selectBox2: NSBox!
  16. @IBOutlet weak var emailBox: NSBox!
  17. @IBOutlet weak var emailTextField: NSTextField!
  18. @IBOutlet weak var emailErrorLabel: NSTextField!
  19. @IBOutlet weak var passwordBox: NSBox!
  20. @IBOutlet weak var verifficationView: NSView!
  21. @IBOutlet weak var verifficationBox: NSBox!
  22. @IBOutlet weak var verifficationTextField: NSTextField!
  23. @IBOutlet weak var sendBox: KMBox!
  24. @IBOutlet weak var sendLabel: NSTextField!
  25. @IBOutlet weak var passwordView: NSView!
  26. @IBOutlet weak var passwordTextField: NSTextField!
  27. @IBOutlet weak var visibleButton: NSButton!
  28. @IBOutlet weak var passwordErrorLabel: NSTextField!
  29. @IBOutlet weak var stayCheckButton: NSButton!
  30. @IBOutlet weak var stayLabel: NSTextField!
  31. @IBOutlet weak var forgetButton: NSButton!
  32. @IBOutlet weak var signUpBox: NSBox!
  33. @IBOutlet weak var signUpButton: NSButton!
  34. @IBOutlet weak var privacyCheckButton: NSButton!
  35. @IBOutlet weak var privacyLabel: NSTextField!
  36. private var viewModel = KMSignUpViewModel()
  37. private var cancellables = Set<AnyCancellable>()
  38. override func draw(_ dirtyRect: NSRect) {
  39. super.draw(dirtyRect)
  40. // Drawing code here.
  41. bindViewModel()
  42. languageLocalized()
  43. initializeUI()
  44. }
  45. // MARK: Private Method
  46. private func languageLocalized() -> Void {
  47. signUpLabel.stringValue = NSLocalizedString("Sign Up", tableName: "MemberCenterLocalizable", comment: "")
  48. verificationCodeButton.title = NSLocalizedString("Verification code", tableName: "MemberCenterLocalizable", comment: "")
  49. passwordButton.title = NSLocalizedString("Password", tableName: "MemberCenterLocalizable", comment: "")
  50. // sendLabel.stringValue = NSLocalizedString("Send", tableName: "MemberCenterLocalizable", comment: "")
  51. stayLabel.stringValue = NSLocalizedString("Stay logged in", tableName: "MemberCenterLocalizable", comment: "")
  52. forgetButton.title = NSLocalizedString("Forget Password?", tableName: "MemberCenterLocalizable", comment: "")
  53. signUpButton.title = NSLocalizedString("Sign Up", tableName: "MemberCenterLocalizable", comment: "")
  54. emailErrorLabel.stringValue = String(format: "*%@", NSLocalizedString("Please enter right Address", tableName: "MemberCenterLocalizable", comment: ""))
  55. passwordErrorLabel.stringValue = String(format: "*%@", NSLocalizedString("Please enter right Verification code", tableName: "MemberCenterLocalizable", comment: ""))
  56. emailTextField.placeholderString = NSLocalizedString("Please enter Email", tableName: "MemberCenterLocalizable", comment: "")
  57. verifficationTextField.placeholderString = NSLocalizedString("Enter Verification code", tableName: "MemberCenterLocalizable", comment: "")
  58. passwordTextField.placeholderString = NSLocalizedString("Password", tableName: "MemberCenterLocalizable", comment: "")
  59. }
  60. private func initializeUI() -> Void {
  61. emailTextField.delegate = self
  62. verifficationTextField.delegate = self
  63. passwordTextField.delegate = self
  64. signUpLabel.textColor = NSColor(named: "000000")
  65. signUpLabel.font = NSFont.SFMediumFontWithSize(20)
  66. selectBox1.fillColor = NSColor(named: "4982E6") ?? NSColor.blue
  67. emailErrorLabel.isHidden = true
  68. emailErrorLabel.textColor = NSColor(named: "FA1E5D")
  69. emailErrorLabel.font = NSFont.SFProTextRegularFont(9)
  70. passwordBox.borderColor = NSColor(named: "DADBDE") ?? NSColor.gray
  71. verifficationBox.borderColor = NSColor(named: "FA1E5D") ?? NSColor.gray
  72. sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
  73. sendBox.borderColor = NSColor(named: "273C62") ?? NSColor.blue
  74. sendLabel.textColor = NSColor(named: "FFFFFF") ?? NSColor.white
  75. sendLabel.font = NSFont.SFProTextRegularFont(16)
  76. passwordErrorLabel.isHidden = true
  77. passwordErrorLabel.textColor = NSColor(named: "FA1E5D")
  78. passwordErrorLabel.font = NSFont.SFProTextRegularFont(9)
  79. stayCheckButton.image = NSImage(named: "CheckBoxNor")
  80. stayLabel.textColor = NSColor(named: "0E1114") ?? NSColor.black
  81. stayLabel.font = NSFont.SFProTextRegularFont(12)
  82. forgetButton.setTitleColor(color: NSColor(named: "4982E6") ?? NSColor.blue, font: NSFont.SFProTextRegularFont(12))
  83. signUpBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
  84. signUpButton.setTitleColor(color: NSColor(named: "FFFFFF") ?? NSColor.white, font: NSFont.SFProTextRegularFont(16))
  85. privacyCheckButton.image = NSImage(named: "CheckBoxNor")
  86. privacyLabel.isEditable = false
  87. privacyLabel.isSelectable = true
  88. privacyLabel.allowsEditingTextAttributes = true
  89. privacyLabel.textColor = NSColor.black
  90. privacyLabel.font = NSFont.SFProTextRegularFont(16.0)
  91. let tipsString = NSLocalizedString("I have read and agree to the %@ and %@, and an account will be automatically created after I log in to an unregistered email address", comment: "")
  92. let specialOffer = NSLocalizedString("User Agreement", comment: "")
  93. let contactsUs = NSLocalizedString("Privacy Policy", comment: "")
  94. let fullString = String(format: tipsString, specialOffer, contactsUs)
  95. let attributedString = NSMutableAttributedString(string: fullString)
  96. // 定义链接的范围
  97. let specialOfferRange = (fullString as NSString).range(of: specialOffer)
  98. let contactsUsRange = (fullString as NSString).range(of: contactsUs)
  99. let linkColor = NSColor(named: "4982E6") ?? NSColor.blue
  100. let font = NSFont.SFProTextRegularFont(11.0) // 与普通文本相同的字体
  101. attributedString.addAttributes([
  102. .foregroundColor: NSColor(named: "0E1114") ?? NSColor.black as Any,
  103. .font: font
  104. ], range: (fullString as NSString).range(of: fullString))
  105. attributedString.addAttributes([
  106. .foregroundColor: linkColor,
  107. .link: NSLocalizedString("https://www.pdfreaderpro.com/store?mode=edu", comment: ""),
  108. .font: font
  109. ], range: specialOfferRange)
  110. attributedString.addAttributes([
  111. .foregroundColor: linkColor,
  112. .link: NSLocalizedString("https://www.pdfreaderpro.com/vpp-purchase-program", comment: ""),
  113. .font: font
  114. ], range: contactsUsRange)
  115. privacyLabel.attributedStringValue = attributedString
  116. signUpStateChange()
  117. visibleStateChange()
  118. textfieldInputState(isEmail: true)
  119. textfieldInputState(isEmail: false)
  120. sendBoxRefresh()
  121. sendBox.moveCallback = { [weak self](mouseEntered: Bool, mouseBox: KMBox) -> Void in
  122. guard let self = self else { return }
  123. if self.viewModel.email.count <= 0 { return }
  124. if self.viewModel.sendBoxSelect { return }
  125. if mouseEntered {
  126. self.sendBox.fillColor = NSColor(named: "000000_0.1") ?? NSColor.blue
  127. self.sendBox.borderWidth = 1
  128. } else {
  129. self.sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
  130. }
  131. }
  132. sendBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in
  133. guard let self = self else { return }
  134. if self.viewModel.email.count <= 0 { return }
  135. if self.viewModel.sendBoxSelect { return }
  136. if downEntered {
  137. self.sendBox.fillColor = NSColor(named: "273C62_0.4") ?? NSColor.blue
  138. viewModel.countDown()
  139. }
  140. }
  141. }
  142. private func signUpStateChange() -> Void {
  143. if viewModel.signUpState == .verificationCode {
  144. selectBox1.isHidden = false
  145. selectBox2.isHidden = true
  146. verificationCodeButton.setTitleColor(color: NSColor(named: "4982E6") ?? NSColor.black, font: NSFont.SFProTextRegularFont(14))
  147. passwordButton.setTitleColor(color: NSColor(named: "42464D") ?? NSColor.black, font: NSFont.SFProTextRegularFont(14))
  148. verifficationView.isHidden = false
  149. passwordView.isHidden = true
  150. passwordTextField.placeholderString = NSLocalizedString("Enter Verification code", tableName: "MemberCenterLocalizable", comment: "")
  151. forgetButton.isHidden = true
  152. } else if viewModel.signUpState == .password {
  153. selectBox1.isHidden = true
  154. selectBox2.isHidden = false
  155. verificationCodeButton.setTitleColor(color: NSColor(named: "42464D") ?? NSColor.black, font: NSFont.SFProTextRegularFont(14))
  156. passwordButton.setTitleColor(color: NSColor(named: "4982E6") ?? NSColor.black, font: NSFont.SFProTextRegularFont(14))
  157. verifficationView.isHidden = true
  158. passwordView.isHidden = false
  159. passwordTextField.placeholderString = NSLocalizedString("Password", tableName: "MemberCenterLocalizable", comment: "")
  160. forgetButton.isHidden = false
  161. }
  162. }
  163. private func checkStateChange(button: NSButton!, state: Bool) -> Void {
  164. button.state = state ? .on : .off
  165. if button.state == .on {
  166. button.image = NSImage(named: "CheckBoxSel")
  167. } else {
  168. button.image = NSImage(named: "CheckBoxNor")
  169. }
  170. }
  171. private func visibleStateChange() -> Void {
  172. if viewModel.isVisible {
  173. visibleButton.image = NSImage(named: "PasswordVisible")
  174. } else {
  175. visibleButton.image = NSImage(named: "PasswordUnVisible")
  176. }
  177. }
  178. private func textfieldInputState(isEmail: Bool) -> Void {
  179. if isEmail {
  180. if viewModel.emailError {
  181. emailBox.borderColor = NSColor(named: "FA1E5D") ?? NSColor.red
  182. } else {
  183. emailBox.borderColor = NSColor(named: "DADBDE") ?? NSColor.gray
  184. }
  185. emailErrorLabel.isHidden = !viewModel.emailError
  186. } else {
  187. if viewModel.passwordError {
  188. if viewModel.signUpState == .verificationCode {
  189. passwordBox.borderWidth = 0
  190. verifficationBox.borderWidth = 1
  191. } else if viewModel.signUpState == .password {
  192. passwordBox.borderWidth = 1
  193. verifficationBox.borderWidth = 0
  194. }
  195. } else {
  196. if viewModel.signUpState == .verificationCode {
  197. passwordBox.borderWidth = 1
  198. verifficationBox.borderWidth = 0
  199. } else if viewModel.signUpState == .password {
  200. passwordBox.borderWidth = 1
  201. verifficationBox.borderWidth = 0
  202. }
  203. }
  204. passwordErrorLabel.isHidden = !viewModel.passwordError
  205. }
  206. }
  207. func sendBoxRefresh() -> Void {
  208. sendLabel.stringValue = viewModel.sendContent
  209. if viewModel.sendContent == NSLocalizedString("Send", tableName: "MemberCenterLocalizable", comment: "") {
  210. if viewModel.email.count > 0 {
  211. sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
  212. } else {
  213. sendBox.fillColor = NSColor(named: "273C62_0.4") ?? NSColor.blue
  214. }
  215. } else {
  216. if viewModel.sendContent == NSLocalizedString("Resend", tableName: "MemberCenterLocalizable", comment: "") {
  217. sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
  218. } else {
  219. sendBox.fillColor = NSColor(named: "DADBDE") ?? NSColor.gray
  220. }
  221. }
  222. }
  223. // MARK: Bind Method
  224. func bindViewModel() -> Void {
  225. viewModel.$isVisible
  226. .receive(on: RunLoop.main)
  227. .sink { [weak self] newValue in
  228. self?.visibleStateChange()
  229. }
  230. .store(in: &cancellables)
  231. viewModel.$stayState
  232. .receive(on: RunLoop.main)
  233. .sink { [weak self] newValue in
  234. self?.checkStateChange(button: self?.stayCheckButton, state: newValue)
  235. }
  236. .store(in: &cancellables)
  237. viewModel.$privacyState
  238. .receive(on: RunLoop.main)
  239. .sink { [weak self] newValue in
  240. self?.checkStateChange(button: self?.privacyCheckButton, state: newValue)
  241. }
  242. .store(in: &cancellables)
  243. viewModel.$signUpState
  244. .receive(on: RunLoop.main)
  245. .sink { [weak self] newValue in
  246. self?.signUpStateChange()
  247. }
  248. .store(in: &cancellables)
  249. viewModel.$emailError
  250. .receive(on: RunLoop.main)
  251. .sink { [weak self] newValue in
  252. self?.textfieldInputState(isEmail: true)
  253. }
  254. .store(in: &cancellables)
  255. viewModel.$passwordError
  256. .receive(on: RunLoop.main)
  257. .sink { [weak self] newValue in
  258. self?.textfieldInputState(isEmail: false)
  259. }
  260. .store(in: &cancellables)
  261. viewModel.$emailErrorMessage
  262. .receive(on: RunLoop.main)
  263. .sink { [weak self] newValue in
  264. self?.emailErrorLabel.stringValue = newValue
  265. self?.emailErrorLabel.isHidden = false
  266. }
  267. .store(in: &cancellables)
  268. viewModel.$passwordErrorMessage
  269. .receive(on: RunLoop.main)
  270. .sink { [weak self] newValue in
  271. self?.passwordErrorLabel.stringValue = newValue
  272. self?.passwordErrorLabel.isHidden = false
  273. }
  274. .store(in: &cancellables)
  275. viewModel.$sendContent
  276. .receive(on: RunLoop.main)
  277. .sink { [weak self] newValue in
  278. self?.sendBoxRefresh()
  279. }
  280. .store(in: &cancellables)
  281. viewModel.$email
  282. .receive(on: RunLoop.main)
  283. .sink { [weak self] newValue in
  284. self?.sendBoxRefresh()
  285. }
  286. .store(in: &cancellables)
  287. }
  288. // MARK: Action Method
  289. @IBAction func verificationCodeAction(_ sender: NSButton) {
  290. viewModel.signUpStateChange(state: .verificationCode)
  291. }
  292. @IBAction func passwordAction(_ sender: NSButton) {
  293. viewModel.signUpStateChange(state: .password)
  294. }
  295. @IBAction func visibleAction(_ sender: NSButton) {
  296. viewModel.isVisible.toggle()
  297. }
  298. @IBAction func stayCheckAction(_ sender: NSButton) {
  299. viewModel.stayState.toggle()
  300. }
  301. @IBAction func signUpAction(_ sender: NSButton) {
  302. viewModel.signUpAction()
  303. }
  304. @IBAction func forgetAction(_ sender: NSButton) {
  305. }
  306. @IBAction func privacyCheckAction(_ sender: NSButton) {
  307. viewModel.privacyState.toggle()
  308. }
  309. }
  310. extension KMSignUpView: NSTextFieldDelegate {
  311. func controlTextDidEndEditing(_ obj: Notification) {
  312. let textField = obj.object as? NSTextField
  313. if textField == emailTextField {
  314. viewModel.email = textField!.stringValue
  315. } else if textField == verifficationTextField {
  316. viewModel.verificationCode = textField!.stringValue
  317. } else if textField == passwordTextField {
  318. viewModel.password = textField!.stringValue
  319. }
  320. }
  321. func controlTextDidChange(_ obj: Notification) {
  322. let textField = obj.object as? NSTextField
  323. if textField == emailTextField {
  324. viewModel.email = textField!.stringValue
  325. } else if textField == verifficationTextField {
  326. viewModel.verificationCode = textField!.stringValue
  327. } else if textField == passwordTextField {
  328. viewModel.password = textField!.stringValue
  329. }
  330. }
  331. }