Browse Source

【会员系统】新增重置密码(输入验证码)UI & UX

wanjun 4 months ago
parent
commit
8503ec03c2

+ 38 - 0
PDF Office/PDF Master/MemberCenter/Assets/MemberCenter.xcassets/Color/0E1114.colorset/Contents.json

@@ -0,0 +1,38 @@
+{
+  "colors" : [
+    {
+      "color" : {
+        "color-space" : "srgb",
+        "components" : {
+          "alpha" : "1.000",
+          "blue" : "0x14",
+          "green" : "0x11",
+          "red" : "0x0E"
+        }
+      },
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "color" : {
+        "color-space" : "srgb",
+        "components" : {
+          "alpha" : "1.000",
+          "blue" : "0x14",
+          "green" : "0x11",
+          "red" : "0x0E"
+        }
+      },
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 251 - 0
PDF Office/PDF Master/MemberCenter/View/KMEnterVerificationCodeView.swift

@@ -0,0 +1,251 @@
+//
+//  KMEnterVerificationCodeView.swift
+//  PDF Reader Pro
+//
+//  Created by wanjun on 2024/10/29.
+//
+
+/**
+  重置密码(输入验证码)
+ */
+
+import Cocoa
+import Combine
+
+class KMEnterVerificationCodeView: KMBaseXibView {
+    
+    @IBOutlet weak var resetPasswordsLabel: NSTextField!
+    @IBOutlet weak var tipLabel: NSTextField!
+    @IBOutlet weak var verifficationView: NSView!
+    @IBOutlet weak var verifficationBox: NSBox!
+    @IBOutlet weak var verifficationTextField: NSTextField!
+    @IBOutlet weak var sendBox: KMBox!
+    @IBOutlet weak var sendLabel: NSTextField!
+    @IBOutlet weak var verifficationErrorLabel: NSTextField!
+    @IBOutlet weak var nextBox: NSBox!
+    @IBOutlet weak var nextButton: NSButton!
+    @IBOutlet weak var backButton: NSButton!
+
+    private var viewModel = KMSignUpViewModel()
+    private var cancellables = Set<AnyCancellable>()
+    
+    convenience init(model: KMSignUpViewModel, superView: NSView) {
+        self.init(frame: superView.bounds)
+        viewModel = model
+
+        loadUI()
+    }
+    
+    public override init(frame frameRect: NSRect) {
+        super.init(frame: frameRect)
+    }
+    
+    public required init?(coder decoder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func updateUI() {
+        super.updateUI()
+        
+        loadUI()
+    }
+    
+    // MARK: Private Method
+    
+    private func loadUI() -> Void {
+        viewModel.sendContent = "60"
+        bindViewModel()
+        languageLocalized()
+        initializeUI()
+        sendBoxRefresh()
+
+        viewModel.countDown(type: .reset)
+        
+        sendBox.moveCallback =  { [weak self](mouseEntered: Bool, mouseBox: KMBox) -> Void in
+            guard let self = self else { return }
+            if self.viewModel.email.count <= 0 { return }
+            if self.viewModel.sendBoxSelect { return }
+            if mouseEntered {
+                self.sendBox.fillColor = NSColor(named: "000000_0.1") ?? NSColor.blue
+                self.sendBox.borderWidth = 1
+            } else {
+                self.sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
+            }
+        }
+        sendBox.downCallback = { [weak self](downEntered: Bool, mouseBox: KMBox, event) -> Void in
+            guard let self = self else { return }
+            if self.viewModel.email.count <= 0 { return }
+            if self.viewModel.sendBoxSelect { return }
+            if downEntered {
+                self.sendBox.fillColor = NSColor(named: "273C62_0.4") ?? NSColor.blue
+                viewModel.countDown(type: .reset)
+            }
+        }
+    }
+    
+    private func languageLocalized() -> Void {
+        resetPasswordsLabel.stringValue = NSLocalizedString("Reset Passwords", tableName: "MemberCenterLocalizable", comment: "")
+        tipLabel.stringValue = String(format: "%@%@", NSLocalizedString("验证码已通过邮件发送至", tableName: "MemberCenterLocalizable", comment: ""), viewModel.email)
+        verifficationTextField.placeholderString = NSLocalizedString("Enter Verification code", tableName: "MemberCenterLocalizable", comment: "")
+        verifficationErrorLabel.stringValue = viewModel.passwordErrorMessage
+        nextButton.title = NSLocalizedString("Next", tableName: "MemberCenterLocalizable", comment: "")
+        backButton.title = NSLocalizedString("Back", tableName: "MemberCenterLocalizable", comment: "")
+    }
+    
+    private func initializeUI() -> Void {
+        verifficationTextField.delegate = self
+
+        resetPasswordsLabel.textColor = NSColor(named: "000000")
+        tipLabel.font = NSFont.SFMediumFontWithSize(20)
+        tipLabel.textColor = NSColor(named: "0E1114")
+        resetPasswordsLabel.font = NSFont.SFProTextRegularFont(12)
+        verifficationTextField.stringValue = viewModel.email
+
+        verifficationErrorLabel.isHidden = viewModel.passwordError()
+        verifficationErrorLabel.textColor = NSColor(named: "FA1E5D")
+        verifficationErrorLabel.font = NSFont.SFProTextRegularFont(9)
+        nextBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
+        nextButton.setTitleColor(color: NSColor(named: "FFFFFF") ?? NSColor.white, font: NSFont.SFProTextRegularFont(16))
+        backButton.setTitleColor(color: NSColor(named: "4982E6") ?? NSColor.blue, font: NSFont.SFProTextRegularFont(12))
+    }
+
+    private func sendBoxRefresh() -> Void {
+        sendLabel.stringValue = viewModel.sendContent
+        if viewModel.sendContent == NSLocalizedString("Send", tableName: "MemberCenterLocalizable", comment: "") {
+            if viewModel.email.count > 0 {
+                sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
+            } else {
+                sendBox.fillColor = NSColor(named: "273C62_0.4") ?? NSColor.blue
+            }
+        } else {
+            if viewModel.sendContent == NSLocalizedString("Resend", tableName: "MemberCenterLocalizable", comment: "") {
+                sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
+            } else {
+                sendBox.fillColor = NSColor(named: "DADBDE") ?? NSColor.gray
+                sendLabel.stringValue = String(format: "%@s", viewModel.sendContent)
+            }
+        }
+    }
+    
+    private func skipEnterNewPasswordView() -> Void {
+        guard let parentView = self.superview else { return }
+        if parentView is NSBox {
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let codeView = KMEnterVerificationCodeView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                codeView.alphaValue = 0
+                (parentView as! NSBox).contentView = codeView
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    codeView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        } else {
+            guard let parentView = self.superview else { return }
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let codeView = KMEnterVerificationCodeView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                codeView.alphaValue = 0
+                parentView.addSubview(codeView)
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    codeView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        }
+    }
+    
+    // MARK: Bind Method
+    
+    func bindViewModel() -> Void {
+        viewModel.$sendContent
+            .receive(on: RunLoop.main)
+            .sink { [weak self] newValue in
+                self?.sendBoxRefresh()
+            }
+            .store(in: &cancellables)
+        viewModel.$passwordErrorMessage
+            .receive(on: RunLoop.main)
+            .sink { [weak self] newValue in
+                self?.verifficationErrorLabel.stringValue = newValue
+                self?.verifficationErrorLabel.isHidden = false
+            }
+            .store(in: &cancellables)
+    }
+
+    // MARK: Action Method
+    
+    @IBAction func nextButtonAction(_ sender: NSButton) {
+        viewModel.passwordErrorMessage = ""
+        viewModel.enterVerificationCodeNextAction() { [weak self] success  in
+            guard let self = self else { return }
+            if success {
+                self.skipEnterNewPasswordView()
+            }
+        }
+    }
+    
+    @IBAction func backButtonAction(_ sender: NSButton) {
+        guard let parentView = self.superview else { return }
+        if parentView is NSBox {
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let forgotView = KMForgotPasswordView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                forgotView.alphaValue = 0
+                (parentView as! NSBox).contentView = forgotView
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    forgotView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        } else {
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let forgotView = KMForgotPasswordView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                forgotView.alphaValue = 0
+                parentView.addSubview(forgotView)
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    forgotView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        }
+    }
+
+}
+
+extension KMEnterVerificationCodeView: NSTextFieldDelegate {
+    func controlTextDidEndEditing(_ obj: Notification) {
+        let textField = obj.object as? NSTextField
+        if textField == verifficationTextField {
+            viewModel.verificationCode = textField!.stringValue
+        }
+    }
+    
+    func controlTextDidChange(_ obj: Notification) {
+        let textField = obj.object as? NSTextField
+        if textField == verifficationTextField {
+            viewModel.verificationCode = textField!.stringValue
+        }
+    }
+}

+ 216 - 0
PDF Office/PDF Master/MemberCenter/View/KMEnterVerificationCodeView.xib

@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+    <dependencies>
+        <deployment identifier="macosx"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="KMEnterVerificationCodeView" customModule="PDF_Reader_Pro" customModuleProvider="target">
+            <connections>
+                <outlet property="backButton" destination="kJt-VF-e2C" id="zyF-Dk-SZA"/>
+                <outlet property="nextBox" destination="Jyk-HC-L8i" id="9Dp-nh-LzV"/>
+                <outlet property="nextButton" destination="78g-DC-UmS" id="1aO-mF-eGU"/>
+                <outlet property="resetPasswordsLabel" destination="QSF-lY-iwc" id="fIm-zN-D4T"/>
+                <outlet property="sendBox" destination="Sn4-mT-M5h" id="GGc-Qd-0gF"/>
+                <outlet property="sendLabel" destination="EBN-jV-4Nt" id="GtU-Zl-bZv"/>
+                <outlet property="tipLabel" destination="LZA-oE-Mth" id="03c-C5-sNT"/>
+                <outlet property="verifficationBox" destination="gAH-oP-4Eg" id="WZN-es-Uo5"/>
+                <outlet property="verifficationErrorLabel" destination="G5c-Rs-bm9" id="brR-1f-bdf"/>
+                <outlet property="verifficationTextField" destination="3WV-H8-R9L" id="bho-d7-8Wr"/>
+                <outlet property="verifficationView" destination="0ZO-1i-5x9" id="8xn-x5-bLT"/>
+            </connections>
+        </customObject>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <customView id="41g-mv-baf">
+            <rect key="frame" x="0.0" y="0.0" width="361" height="443"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <subviews>
+                <box boxType="custom" borderWidth="0.0" title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="cZK-vl-C11">
+                    <rect key="frame" x="46" y="130" width="279" height="184"/>
+                    <view key="contentView" id="Eh5-bs-cIE">
+                        <rect key="frame" x="0.0" y="0.0" width="279" height="184"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <customView translatesAutoresizingMaskIntoConstraints="NO" id="GKZ-Rg-mDm">
+                                <rect key="frame" x="0.0" y="160" width="279" height="24"/>
+                                <subviews>
+                                    <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="QSF-lY-iwc">
+                                        <rect key="frame" x="-2" y="4" width="37" height="16"/>
+                                        <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="KuR-yV-OTv">
+                                            <font key="font" usesAppearanceFont="YES"/>
+                                            <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                        </textFieldCell>
+                                    </textField>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstItem="QSF-lY-iwc" firstAttribute="centerY" secondItem="GKZ-Rg-mDm" secondAttribute="centerY" id="Yci-nm-hOo"/>
+                                    <constraint firstItem="QSF-lY-iwc" firstAttribute="leading" secondItem="GKZ-Rg-mDm" secondAttribute="leading" id="j0i-gE-mOI"/>
+                                    <constraint firstAttribute="height" constant="24" id="zim-hQ-7KH"/>
+                                </constraints>
+                            </customView>
+                            <box boxType="custom" borderWidth="0.0" cornerRadius="1" title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="Jyk-HC-L8i">
+                                <rect key="frame" x="0.0" y="26" width="279" height="32"/>
+                                <view key="contentView" id="nvg-Vl-nH2">
+                                    <rect key="frame" x="0.0" y="0.0" width="279" height="32"/>
+                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                    <subviews>
+                                        <button translatesAutoresizingMaskIntoConstraints="NO" id="78g-DC-UmS">
+                                            <rect key="frame" x="0.0" y="0.0" width="279" height="32"/>
+                                            <buttonCell key="cell" type="bevel" title="Button" bezelStyle="rounded" alignment="center" imageScaling="proportionallyDown" inset="2" id="XcE-DJ-jzy">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="nextButtonAction:" target="-2" id="lm9-P7-oBe"/>
+                                            </connections>
+                                        </button>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="78g-DC-UmS" firstAttribute="leading" secondItem="nvg-Vl-nH2" secondAttribute="leading" id="85Z-NM-2Yu"/>
+                                        <constraint firstAttribute="bottom" secondItem="78g-DC-UmS" secondAttribute="bottom" id="Z4H-1S-bfB"/>
+                                        <constraint firstItem="78g-DC-UmS" firstAttribute="top" secondItem="nvg-Vl-nH2" secondAttribute="top" id="k2g-bH-gMZ"/>
+                                        <constraint firstAttribute="trailing" secondItem="78g-DC-UmS" secondAttribute="trailing" id="pN2-bT-ulO"/>
+                                    </constraints>
+                                </view>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="32" id="eHw-F1-1mX"/>
+                                </constraints>
+                            </box>
+                            <button translatesAutoresizingMaskIntoConstraints="NO" id="kJt-VF-e2C">
+                                <rect key="frame" x="117" y="0.0" width="45" height="16"/>
+                                <buttonCell key="cell" type="bevel" title="Button" bezelStyle="rounded" alignment="center" imageScaling="proportionallyDown" inset="2" id="osJ-gh-dqA">
+                                    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                    <font key="font" metaFont="system"/>
+                                </buttonCell>
+                                <connections>
+                                    <action selector="backButtonAction:" target="-2" id="1bI-9s-htJ"/>
+                                </connections>
+                            </button>
+                            <customView translatesAutoresizingMaskIntoConstraints="NO" id="Cfy-N6-c4n">
+                                <rect key="frame" x="0.0" y="134" width="279" height="14"/>
+                                <subviews>
+                                    <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="LZA-oE-Mth">
+                                        <rect key="frame" x="-2" y="-1" width="37" height="16"/>
+                                        <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="oxN-El-oBZ">
+                                            <font key="font" usesAppearanceFont="YES"/>
+                                            <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                        </textFieldCell>
+                                    </textField>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstItem="LZA-oE-Mth" firstAttribute="centerY" secondItem="Cfy-N6-c4n" secondAttribute="centerY" id="A9h-YE-nIV"/>
+                                    <constraint firstAttribute="height" constant="14" id="RTv-D8-mbf"/>
+                                    <constraint firstItem="LZA-oE-Mth" firstAttribute="leading" secondItem="Cfy-N6-c4n" secondAttribute="leading" id="jRx-ap-yh4"/>
+                                </constraints>
+                            </customView>
+                            <customView translatesAutoresizingMaskIntoConstraints="NO" id="0ZO-1i-5x9">
+                                <rect key="frame" x="0.0" y="82" width="279" height="28"/>
+                                <subviews>
+                                    <box boxType="custom" cornerRadius="1" title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="gAH-oP-4Eg">
+                                        <rect key="frame" x="0.0" y="0.0" width="226" height="28"/>
+                                        <view key="contentView" id="5R5-GG-fog">
+                                            <rect key="frame" x="1" y="1" width="224" height="26"/>
+                                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                            <subviews>
+                                                <textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3WV-H8-R9L">
+                                                    <rect key="frame" x="6" y="5" width="212" height="16"/>
+                                                    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" id="Fux-Lx-ckR">
+                                                        <font key="font" usesAppearanceFont="YES"/>
+                                                        <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                        <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                    </textFieldCell>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstAttribute="trailing" secondItem="3WV-H8-R9L" secondAttribute="trailing" constant="8" id="efX-Rg-79O"/>
+                                                <constraint firstItem="3WV-H8-R9L" firstAttribute="leading" secondItem="5R5-GG-fog" secondAttribute="leading" constant="8" id="odr-gT-aQE"/>
+                                            </constraints>
+                                        </view>
+                                        <constraints>
+                                            <constraint firstItem="3WV-H8-R9L" firstAttribute="centerY" secondItem="gAH-oP-4Eg" secondAttribute="centerY" id="8br-Ib-nKJ"/>
+                                        </constraints>
+                                    </box>
+                                    <box boxType="custom" borderWidth="0.0" cornerRadius="1" title="Box" translatesAutoresizingMaskIntoConstraints="NO" id="Sn4-mT-M5h" customClass="KMBox" customModule="PDF_Reader_Pro" customModuleProvider="target">
+                                        <rect key="frame" x="226" y="0.0" width="53" height="28"/>
+                                        <view key="contentView" id="0pK-Pr-2qe">
+                                            <rect key="frame" x="0.0" y="0.0" width="53" height="28"/>
+                                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                            <subviews>
+                                                <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="EBN-jV-4Nt">
+                                                    <rect key="frame" x="6" y="6" width="41" height="16"/>
+                                                    <textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Label" id="imF-dG-EJc">
+                                                        <font key="font" usesAppearanceFont="YES"/>
+                                                        <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                                        <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                    </textFieldCell>
+                                                </textField>
+                                            </subviews>
+                                            <constraints>
+                                                <constraint firstItem="EBN-jV-4Nt" firstAttribute="leading" secondItem="0pK-Pr-2qe" secondAttribute="leading" constant="8" id="9cV-Bo-stq"/>
+                                                <constraint firstAttribute="trailing" secondItem="EBN-jV-4Nt" secondAttribute="trailing" constant="8" id="eNb-8X-7oz"/>
+                                            </constraints>
+                                        </view>
+                                        <constraints>
+                                            <constraint firstItem="EBN-jV-4Nt" firstAttribute="centerY" secondItem="Sn4-mT-M5h" secondAttribute="centerY" id="3FV-vc-FUN"/>
+                                        </constraints>
+                                    </box>
+                                </subviews>
+                                <constraints>
+                                    <constraint firstItem="Sn4-mT-M5h" firstAttribute="leading" secondItem="gAH-oP-4Eg" secondAttribute="trailing" id="69c-Bl-L8K"/>
+                                    <constraint firstAttribute="trailing" secondItem="Sn4-mT-M5h" secondAttribute="trailing" id="73j-a8-ij9"/>
+                                    <constraint firstItem="gAH-oP-4Eg" firstAttribute="top" secondItem="0ZO-1i-5x9" secondAttribute="top" id="MbZ-4m-fbo"/>
+                                    <constraint firstAttribute="bottom" secondItem="Sn4-mT-M5h" secondAttribute="bottom" id="NkG-Fa-iPF"/>
+                                    <constraint firstItem="gAH-oP-4Eg" firstAttribute="leading" secondItem="0ZO-1i-5x9" secondAttribute="leading" id="Py8-JE-Bgw"/>
+                                    <constraint firstItem="Sn4-mT-M5h" firstAttribute="top" secondItem="0ZO-1i-5x9" secondAttribute="top" id="Qmy-GS-QJj"/>
+                                    <constraint firstAttribute="height" constant="28" id="YYf-ct-PHc"/>
+                                    <constraint firstAttribute="bottom" secondItem="gAH-oP-4Eg" secondAttribute="bottom" id="hbg-kO-8TQ"/>
+                                </constraints>
+                            </customView>
+                            <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="G5c-Rs-bm9">
+                                <rect key="frame" x="-2" y="66" width="283" height="16"/>
+                                <textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="J6k-lX-XBH">
+                                    <font key="font" usesAppearanceFont="YES"/>
+                                    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                </textFieldCell>
+                            </textField>
+                        </subviews>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="Jyk-HC-L8i" secondAttribute="trailing" id="1fr-Nw-0Np"/>
+                            <constraint firstItem="0ZO-1i-5x9" firstAttribute="leading" secondItem="Eh5-bs-cIE" secondAttribute="leading" id="3qa-6Z-kj0"/>
+                            <constraint firstItem="G5c-Rs-bm9" firstAttribute="top" secondItem="0ZO-1i-5x9" secondAttribute="bottom" id="6Fy-5e-YkO"/>
+                            <constraint firstAttribute="trailing" secondItem="GKZ-Rg-mDm" secondAttribute="trailing" id="FHK-fJ-oyA"/>
+                            <constraint firstItem="Jyk-HC-L8i" firstAttribute="leading" secondItem="Eh5-bs-cIE" secondAttribute="leading" id="Hef-Dw-hdR"/>
+                            <constraint firstItem="G5c-Rs-bm9" firstAttribute="leading" secondItem="Eh5-bs-cIE" secondAttribute="leading" id="L3k-Xn-6SZ"/>
+                            <constraint firstAttribute="trailing" secondItem="Cfy-N6-c4n" secondAttribute="trailing" id="Mja-0K-JQN"/>
+                            <constraint firstAttribute="trailing" secondItem="0ZO-1i-5x9" secondAttribute="trailing" id="OEI-ap-cb4"/>
+                            <constraint firstItem="GKZ-Rg-mDm" firstAttribute="leading" secondItem="Eh5-bs-cIE" secondAttribute="leading" id="R7c-pg-tuV"/>
+                            <constraint firstItem="Cfy-N6-c4n" firstAttribute="top" secondItem="GKZ-Rg-mDm" secondAttribute="bottom" constant="12" id="Z4R-FK-UDW"/>
+                            <constraint firstItem="Cfy-N6-c4n" firstAttribute="leading" secondItem="Eh5-bs-cIE" secondAttribute="leading" id="Zc2-a4-KGU"/>
+                            <constraint firstAttribute="bottom" secondItem="kJt-VF-e2C" secondAttribute="bottom" id="dt8-Xu-h3X"/>
+                            <constraint firstAttribute="trailing" secondItem="G5c-Rs-bm9" secondAttribute="trailing" id="kon-2N-oLb"/>
+                            <constraint firstItem="Jyk-HC-L8i" firstAttribute="top" secondItem="0ZO-1i-5x9" secondAttribute="bottom" constant="24" id="lWN-7y-yYS"/>
+                            <constraint firstItem="GKZ-Rg-mDm" firstAttribute="top" secondItem="Eh5-bs-cIE" secondAttribute="top" id="tbr-6v-kdA"/>
+                            <constraint firstItem="0ZO-1i-5x9" firstAttribute="top" secondItem="Cfy-N6-c4n" secondAttribute="bottom" constant="24" id="wWW-Uc-8BH"/>
+                        </constraints>
+                    </view>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="184" id="9wC-Kf-nwb"/>
+                        <constraint firstItem="kJt-VF-e2C" firstAttribute="centerX" secondItem="cZK-vl-C11" secondAttribute="centerX" id="OXJ-PV-PUz"/>
+                        <constraint firstAttribute="width" constant="279" id="uM6-Q3-v1e"/>
+                    </constraints>
+                </box>
+            </subviews>
+            <constraints>
+                <constraint firstItem="cZK-vl-C11" firstAttribute="leading" secondItem="41g-mv-baf" secondAttribute="leading" constant="46" id="18e-dl-cgg"/>
+                <constraint firstItem="cZK-vl-C11" firstAttribute="centerY" secondItem="41g-mv-baf" secondAttribute="centerY" id="TGF-ap-7YT"/>
+                <constraint firstAttribute="trailing" secondItem="cZK-vl-C11" secondAttribute="trailing" constant="36" id="jgO-rR-E6L"/>
+            </constraints>
+            <point key="canvasLocation" x="-57.5" y="114.5"/>
+        </customView>
+    </objects>
+</document>

+ 43 - 44
PDF Office/PDF Master/MemberCenter/View/KMForgotPasswordView.swift

@@ -21,10 +21,10 @@ class KMForgotPasswordView: KMBaseXibView {
     private var viewModel = KMSignUpViewModel()
     private var cancellables = Set<AnyCancellable>()
     
-    convenience init(email: String, superView: NSView) {
+    convenience init(model: KMSignUpViewModel, superView: NSView) {
         self.init(frame: superView.bounds)
-        viewModel.email = email
-        
+        viewModel = model
+
         bindViewModel()
         languageLocalized()
         initializeUI()
@@ -62,7 +62,7 @@ class KMForgotPasswordView: KMBaseXibView {
         resetPasswordsLabel.textColor = NSColor(named: "000000")
         resetPasswordsLabel.font = NSFont.SFMediumFontWithSize(20)
         emailTextField.stringValue = viewModel.email
-        emailErrorLabel.isHidden = true
+        emailErrorLabel.isHidden = viewModel.emailError()
         emailErrorLabel.textColor = NSColor(named: "FA1E5D")
         emailErrorLabel.font = NSFont.SFProTextRegularFont(9)
         nextBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
@@ -71,12 +71,12 @@ class KMForgotPasswordView: KMBaseXibView {
     }
     
     private func textfieldInputState() -> Void {
-        if viewModel.emailError {
+        if viewModel.emailError() {
             emailBox.borderColor = NSColor(named: "FA1E5D") ?? NSColor.red
         } else {
             emailBox.borderColor = NSColor(named: "DADBDE") ?? NSColor.gray
         }
-        emailErrorLabel.isHidden = !viewModel.emailError
+        emailErrorLabel.isHidden = !viewModel.emailError()
     }
     
     private func skipSignUpView() -> Void {
@@ -118,48 +118,46 @@ class KMForgotPasswordView: KMBaseXibView {
     }
     
     private func skipEnterVerificationCodeView() -> Void {
-//        guard let parentView = self.superview else { return }
-//        if parentView is NSBox {
-//            let signUpView = KMSignUpView(frame: parentView.bounds)
-//            NSAnimationContext.runAnimationGroup { context in
-//                context.duration = 0.3
-//                self.animator().alphaValue = 0
-//            } completionHandler: {
-//                self.removeFromSuperview()
-//                signUpView.alphaValue = 0
-//                (parentView as! NSBox).contentView = signUpView
-//                NSAnimationContext.runAnimationGroup({ context in
-//                    context.duration = 0.3
-//                    signUpView.animator().alphaValue = 1
-//                }, completionHandler: nil)
-//            }
-//        } else {
-//            guard let parentView = self.superview else { return }
-//            let signUpView = KMSignUpView(frame: parentView.bounds)
-//            NSAnimationContext.runAnimationGroup { context in
-//                context.duration = 0.3
-//                self.animator().alphaValue = 0
-//            } completionHandler: {
-//                self.removeFromSuperview()
-//                signUpView.alphaValue = 0
-//                parentView.addSubview(signUpView)
-//                NSAnimationContext.runAnimationGroup({ context in
-//                    context.duration = 0.3
-//                    signUpView.animator().alphaValue = 1
-//                }, completionHandler: nil)
-//            }
-//        }
+        guard let parentView = self.superview else { return }
+        if parentView is NSBox {
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let codeView = KMEnterVerificationCodeView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                codeView.alphaValue = 0
+                (parentView as! NSBox).contentView = codeView
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    codeView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        } else {
+            guard let parentView = self.superview else { return }
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let codeView = KMEnterVerificationCodeView(model: model, superView: parentView)
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.3
+                self.animator().alphaValue = 0
+            } completionHandler: {
+                self.removeFromSuperview()
+                codeView.alphaValue = 0
+                parentView.addSubview(codeView)
+                NSAnimationContext.runAnimationGroup({ context in
+                    context.duration = 0.3
+                    codeView.animator().alphaValue = 1
+                }, completionHandler: nil)
+            }
+        }
     }
     
     // MARK: Bind Method
     
     func bindViewModel() -> Void {
-        viewModel.$emailError
-            .receive(on: RunLoop.main)
-            .sink { [weak self] newValue in
-                self?.textfieldInputState()
-            }
-            .store(in: &cancellables)
         viewModel.$emailErrorMessage
             .receive(on: RunLoop.main)
             .sink { [weak self] newValue in
@@ -172,7 +170,8 @@ class KMForgotPasswordView: KMBaseXibView {
     // MARK: Action Method
     
     @IBAction func nextButtonAction(_ sender: NSButton) {
-        viewModel.nextAction() { [weak self] success  in
+        viewModel.emailErrorMessage = ""
+        viewModel.forgotPasswordNextAction() { [weak self] success  in
             guard let self = self else { return }
             if success {
                 self.skipEnterVerificationCodeView()

+ 16 - 23
PDF Office/PDF Master/MemberCenter/View/KMSignUpView.swift

@@ -73,7 +73,6 @@ class KMSignUpView: KMBaseXibView {
         signUpLabel.stringValue = NSLocalizedString("Sign Up", tableName: "MemberCenterLocalizable", comment: "")
         verificationCodeButton.title = NSLocalizedString("Verification code", tableName: "MemberCenterLocalizable", comment: "")
         passwordButton.title = NSLocalizedString("Password", tableName: "MemberCenterLocalizable", comment: "")
-//        sendLabel.stringValue = NSLocalizedString("Send", tableName: "MemberCenterLocalizable", comment: "")
         stayLabel.stringValue = NSLocalizedString("Stay logged in", tableName: "MemberCenterLocalizable", comment: "")
         forgetButton.title = NSLocalizedString("Forget Password?", tableName: "MemberCenterLocalizable", comment: "")
         signUpButton.title = NSLocalizedString("Sign Up", tableName: "MemberCenterLocalizable", comment: "")
@@ -96,8 +95,8 @@ class KMSignUpView: KMBaseXibView {
         verifficationTextField.stringValue = viewModel.verificationCode
         passwordTextField.stringValue = viewModel.password
         passwordTextField1.stringValue = viewModel.password
-        emailErrorLabel.isHidden = !viewModel.emailError
-        passwordErrorLabel.isHidden = !viewModel.passwordError
+        emailErrorLabel.isHidden = !viewModel.emailError()
+        passwordErrorLabel.isHidden = !viewModel.passwordError()
 
         signUpLabel.textColor = NSColor(named: "000000")
         signUpLabel.font = NSFont.SFMediumFontWithSize(20)
@@ -173,7 +172,7 @@ class KMSignUpView: KMBaseXibView {
             if self.viewModel.sendBoxSelect { return }
             if downEntered {
                 self.sendBox.fillColor = NSColor(named: "273C62_0.4") ?? NSColor.blue
-                viewModel.countDown()
+                viewModel.countDown(type: .login)
             }
         }
     }
@@ -226,14 +225,14 @@ class KMSignUpView: KMBaseXibView {
     
     private func textfieldInputState(isEmail: Bool) -> Void {
         if isEmail {
-            if viewModel.emailError {
+            if viewModel.emailError() {
                 emailBox.borderColor = NSColor(named: "FA1E5D") ?? NSColor.red
             } else {
                 emailBox.borderColor = NSColor(named: "DADBDE") ?? NSColor.gray
             }
-            emailErrorLabel.isHidden = !viewModel.emailError
+            emailErrorLabel.isHidden = !viewModel.emailError()
         } else {
-            if viewModel.passwordError {
+            if viewModel.passwordError() {
                 if viewModel.signUpState == .verificationCode {
                     passwordBox.borderWidth = 0
                     verifficationBox.borderWidth = 1
@@ -250,7 +249,7 @@ class KMSignUpView: KMBaseXibView {
                     verifficationBox.borderWidth = 0
                 }
             }
-            passwordErrorLabel.isHidden = !viewModel.passwordError
+            passwordErrorLabel.isHidden = !viewModel.passwordError()
         }
     }
     
@@ -267,6 +266,7 @@ class KMSignUpView: KMBaseXibView {
                 sendBox.fillColor = NSColor(named: "273C62") ?? NSColor.blue
             } else {
                 sendBox.fillColor = NSColor(named: "DADBDE") ?? NSColor.gray
+                sendLabel.stringValue = String(format: "%@s", viewModel.sendContent)
             }
         }
     }
@@ -298,18 +298,6 @@ class KMSignUpView: KMBaseXibView {
                 self?.signUpStateChange()
             }
             .store(in: &cancellables)
-        viewModel.$emailError
-            .receive(on: RunLoop.main)
-            .sink { [weak self] newValue in
-                self?.textfieldInputState(isEmail: true)
-            }
-            .store(in: &cancellables)
-        viewModel.$passwordError
-            .receive(on: RunLoop.main)
-            .sink { [weak self] newValue in
-                self?.textfieldInputState(isEmail: false)
-            }
-            .store(in: &cancellables)
         viewModel.$emailErrorMessage
             .receive(on: RunLoop.main)
             .sink { [weak self] newValue in
@@ -357,14 +345,17 @@ class KMSignUpView: KMBaseXibView {
     }
     
     @IBAction func signUpAction(_ sender: NSButton) {
+        viewModel.emailErrorMessage = ""
+        viewModel.passwordErrorMessage = ""
         viewModel.signUpAction()
     }
     
     @IBAction func forgetAction(_ sender: NSButton) {
         guard let parentView = self.superview else { return }
         if parentView is NSBox {
-//            let forgotView = KMForgotPasswordView(frame: parentView.bounds)
-            let forgotView = KMForgotPasswordView(email: viewModel.email, superView: parentView)
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let forgotView = KMForgotPasswordView(model: model, superView: parentView)
             NSAnimationContext.runAnimationGroup { context in
                 context.duration = 0.3
                 self.animator().alphaValue = 0
@@ -378,7 +369,9 @@ class KMSignUpView: KMBaseXibView {
                 }, completionHandler: nil)
             }
         } else {
-            let forgotView = KMForgotPasswordView(email: viewModel.email, superView: parentView)
+            let model = KMSignUpViewModel()
+            model.email = viewModel.email
+            let forgotView = KMForgotPasswordView(model: model, superView: parentView)
             NSAnimationContext.runAnimationGroup { context in
                 context.duration = 0.3
                 self.animator().alphaValue = 0

+ 59 - 58
PDF Office/PDF Master/MemberCenter/ViewModel/KMSignUpViewModel.swift

@@ -13,19 +13,6 @@ import Combine
     case password               // 密码
 }
 
-//// Email错误提示样式
-//@objc enum KMEmailErrorMessageType : Int {
-//    case existingAccount = 0   // 输入邮箱错误 - 已有账号
-//    case formattingError // 输入邮箱错误 - 邮箱格式错误
-//}
-//
-//// 验证码 & 密码 错误提示样式
-//@objc enum KMPasswordErrorMessageType : Int {
-//    case characterLack = 0 // 输入密码错误 - 密码字符不够
-//    case characterOverlong // 输入密码错误 - 密码字符过长
-//    case verificationError // 二次确认密码错误
-//}
-
 typealias ForgotPasswordComplete = (_ success: Bool) -> Void
 
 class KMSignUpViewModel: ObservableObject {
@@ -57,14 +44,6 @@ class KMSignUpViewModel: ObservableObject {
      用户邮箱登录的密码,字符串格式,默认为空
      */
     @Published var password: String = ""
-    /**
-     邮箱格式错误
-     */
-    @Published var emailError: Bool = false
-    /**
-     验证码 / 密码 格式错误
-     */
-    @Published var passwordError: Bool = false
     /**
      邮件 错误提示文案
      */
@@ -96,32 +75,8 @@ class KMSignUpViewModel: ObservableObject {
         }
     }
     
-//    func getEmailErrorMessage() -> Void {
-//        
-//        switch emailErrorMessageType {
-//        case .existingAccount:
-//            emailErrorMessage = NSLocalizedString("This account is registered", tableName: "MemberCenterLocalizable", comment: "")
-//            break
-//        case .emailFormattingError:
-//            emailErrorMessage = NSLocalizedString("Please enter the correct email format", tableName: "MemberCenterLocalizable", comment: "")
-//            break
-//        case .passwordCharacterLack:
-//            errorMessage = NSLocalizedString("At least 6 characters", tableName: "MemberCenterLocalizable", comment: "")
-//            break
-//        case .passwordCharacterOverlong:
-//            errorMessage = NSLocalizedString("Up to 24 characters", tableName: "MemberCenterLocalizable", comment: "")
-//            break
-//        case .secondaryVerificationError:
-//            errorMessage = NSLocalizedString("*Password inconsistency", tableName: "MemberCenterLocalizable", comment: "")
-//            break
-//        default:
-//            
-//            break
-//        }
-//    }
-    
-    func countDown(count: Int = 60) -> Void {
-        getVerificationCode()
+    func countDown(type: KMVerificationCodeType, count: Int = 60) -> Void {
+        getVerificationCode(type: type)
         if emailErrorMessage.count > 0 {
             return
         }
@@ -146,6 +101,29 @@ class KMSignUpViewModel: ObservableObject {
     
     // MARK: Public Method
     
+    /**
+     邮件 错误提示文案
+     */
+    func emailError() -> Bool {
+        if emailErrorMessage.count > 0 {
+            return true
+        }
+        return false
+    }
+    
+    /**
+     验证码 / 密码 格式错误
+     */
+    func passwordError() -> Bool {
+        if passwordErrorMessage.count > 0 {
+            return true
+        }
+        return false
+    }
+
+    
+    // MARK: Private Method
+    
     /**
      @abstract 验证邮箱是否合规
      */
@@ -155,9 +133,15 @@ class KMSignUpViewModel: ObservableObject {
         return emailTest.evaluate(with: email)
     }
     
-    // MARK: Private Method
-    
-    
+    /**
+     @abstract 验证验证码是否合规
+     */
+    private func isValidVerificationCode() -> Bool {
+        let pattern = "^\\d{6}$"
+        let regex = try! NSRegularExpression(pattern: pattern)
+        return regex.firstMatch(in: verificationCode, options: [], range: NSRange(location: 0, length: verificationCode.utf16.count)) != nil
+    }
+        
     // MARK: Action Method
     
     /**
@@ -166,15 +150,15 @@ class KMSignUpViewModel: ObservableObject {
      */
     func signUpAction() -> Void {
         if email.count <= 0 {
-            emailError = true
+            emailErrorMessage = NSLocalizedString("Please enter the correct email format", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
         if verificationCode.count <= 0 {
-            passwordError = true
+            passwordErrorMessage = NSLocalizedString("*Please enter right Verification code", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
         if password.count <= 0 {
-            passwordError = true
+            passwordErrorMessage = NSLocalizedString("*Please enter right Verification code", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
         
@@ -204,15 +188,14 @@ class KMSignUpViewModel: ObservableObject {
      @abstract KMForgotPasswordView 登录弹窗(忘记密码)Next 按钮响应事件
      @param
      */
-    func nextAction(complete: @escaping ForgotPasswordComplete) -> Void {
-        emailErrorMessage = ""
+    func forgotPasswordNextAction(complete: @escaping ForgotPasswordComplete) -> Void {
         if !isValidEmail() {
             emailErrorMessage = NSLocalizedString("Please enter the correct email format", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
 
         if email.count <= 0 {
-            emailError = true
+            emailErrorMessage = NSLocalizedString("Please enter the correct email format", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
         if emailErrorMessage.count > 0 {
@@ -236,16 +219,34 @@ class KMSignUpViewModel: ObservableObject {
         }
     }
     
+    /**
+     @abstract KMEnterVerificationCodeView 登录弹窗(输入验证码)Next 按钮响应事件
+     @param
+     */
+    func enterVerificationCodeNextAction(complete: @escaping ForgotPasswordComplete) -> Void {
+        if verificationCode.count <= 0 {
+            emailErrorMessage = NSLocalizedString("*Please enter right Verification code", tableName: "MemberCenterLocalizable", comment: "")
+            complete(false)
+            return
+        }
+        if !isValidVerificationCode() {
+            emailErrorMessage = NSLocalizedString("*Please enter right Verification code", tableName: "MemberCenterLocalizable", comment: "")
+            complete(false)
+            return
+        }
+        complete(true)
+    }
+    
     /**
      @abstract 获取邮箱验证码
      @param
      */
-    func getVerificationCode() -> Void {
+    func getVerificationCode(type: KMVerificationCodeType) -> Void {
         if !isValidEmail() {
             emailErrorMessage = NSLocalizedString("Please enter the correct email format", tableName: "MemberCenterLocalizable", comment: "")
             return
         }
-        KMMemberCenterManager.manager.getVerificationCode(action: .login, receiver: email) { [weak self] error, wrapper  in
+        KMMemberCenterManager.manager.getVerificationCode(action: type, receiver: email) { [weak self] error, wrapper  in
             guard let self = self else { return }
             let resultDict = wrapper! as KMMemberCenterResult
             let msg = resultDict.msg

+ 2 - 3
PDF Office/PDF Master/MemberCenter/WindowsController/KMLoginWindowsController.swift

@@ -6,7 +6,6 @@
 //
 
 import Cocoa
-import SwiftUI
 
 class KMLoginWindowsController: NSWindowController {
     
@@ -21,8 +20,8 @@ class KMLoginWindowsController: NSWindowController {
         super.windowDidLoad()
 
         // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
-        window?.styleMask.insert([.titled, .closable, .miniaturizable, .fullSizeContentView])
-        window?.titleVisibility = .visible
+//        window?.styleMask.insert([.titled, .closable, .miniaturizable, .fullSizeContentView])
+//        window?.titleVisibility = .visible
         
         initializeUI()
     }

+ 16 - 0
PDF Office/PDF Reader Pro.xcodeproj/project.pbxproj

@@ -1125,6 +1125,12 @@
 		9FC3464D2CCFA9D600F35823 /* KMForgotPasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC3464C2CCFA9D600F35823 /* KMForgotPasswordView.xib */; };
 		9FC3464E2CCFA9D600F35823 /* KMForgotPasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC3464C2CCFA9D600F35823 /* KMForgotPasswordView.xib */; };
 		9FC3464F2CCFA9D600F35823 /* KMForgotPasswordView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC3464C2CCFA9D600F35823 /* KMForgotPasswordView.xib */; };
+		9FC346552CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC346542CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift */; };
+		9FC346562CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC346542CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift */; };
+		9FC346572CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC346542CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift */; };
+		9FC346592CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC346582CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib */; };
+		9FC3465A2CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC346582CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib */; };
+		9FC3465B2CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9FC346582CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib */; };
 		9FC444FA2AA61EDE00D7187C /* ZipArchive.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC444F82AA5F7D600D7187C /* ZipArchive.framework */; };
 		9FC444FB2AA61EDE00D7187C /* ZipArchive.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC444F82AA5F7D600D7187C /* ZipArchive.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		9FCFEC682AC2EAD500EAD2CB /* CPDFListViewColorMenuItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCFEC672AC2EAD500EAD2CB /* CPDFListViewColorMenuItemView.swift */; };
@@ -6125,6 +6131,8 @@
 		9FBDA72C2A4D532700A972F3 /* KMWebsocketManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMWebsocketManager.swift; sourceTree = "<group>"; };
 		9FC346442CCFA96800F35823 /* KMForgotPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMForgotPasswordView.swift; sourceTree = "<group>"; };
 		9FC3464C2CCFA9D600F35823 /* KMForgotPasswordView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMForgotPasswordView.xib; sourceTree = "<group>"; };
+		9FC346542CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMEnterVerificationCodeView.swift; sourceTree = "<group>"; };
+		9FC346582CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMEnterVerificationCodeView.xib; sourceTree = "<group>"; };
 		9FC444F82AA5F7D600D7187C /* ZipArchive.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = ZipArchive.framework; sourceTree = "<group>"; };
 		9FCFEC672AC2EAD500EAD2CB /* CPDFListViewColorMenuItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPDFListViewColorMenuItemView.swift; sourceTree = "<group>"; };
 		9FCFEC6B2AC3D96800EAD2CB /* CPDFListViewAnimatedBorderlessWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPDFListViewAnimatedBorderlessWindow.swift; sourceTree = "<group>"; };
@@ -9019,6 +9027,8 @@
 				9F58E8882CC8CD07002457F1 /* KMSignUpView.xib */,
 				9FC346442CCFA96800F35823 /* KMForgotPasswordView.swift */,
 				9FC3464C2CCFA9D600F35823 /* KMForgotPasswordView.xib */,
+				9FC346542CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift */,
+				9FC346582CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib */,
 			);
 			path = View;
 			sourceTree = "<group>";
@@ -15450,6 +15460,7 @@
 				9F8539DA294318D600DF644E /* TabsImage.xcassets in Resources */,
 				BBA8B7B3293635D80097D183 /* KMPasswordInputWindow.xib in Resources */,
 				8997010128F40710009AF911 /* KMBookMarkViewController.xib in Resources */,
+				9FC346592CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */,
 				89E4E7382964148E002DBA6F /* KMAnnotationPropertiesViewController.xib in Resources */,
 				BB897231294B08DE0045787C /* KMWatermarkViewController.xib in Resources */,
 				9F56648A2988B16F00020985 /* KMTextfieldVC.xib in Resources */,
@@ -16023,6 +16034,7 @@
 				AD3AAD602B0DA3D400DE5FE7 /* KMCompareTextViewItem.xib in Resources */,
 				ADD1B6F52946C07800C3FFF7 /* KMPrintChoosePageSizePosterView.xib in Resources */,
 				BB031B882C47BB090099F7AD /* KMUserFbTypeItemView.xib in Resources */,
+				9FC3465A2CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */,
 				BB9007042B8DDCE400623B78 /* SyncPreferences.xib in Resources */,
 				9F1FE3F5293F4F0F00E952CA /* Info.plist in Resources */,
 				BB7648E929ECECBF00931039 /* Color.xcassets in Resources */,
@@ -16177,6 +16189,7 @@
 				AD2D74B229F0CEB300EDC5E4 /* KMCancellationWindowController.xib in Resources */,
 				9F853A042947137500DF644E /* default-icon.pdf in Resources */,
 				ADE86AF42B0AF56C00414DFA /* KMCompareCoveringSettingView.xib in Resources */,
+				9FC3465B2CD0C7ED00F35823 /* KMEnterVerificationCodeView.xib in Resources */,
 				9F8539ED2947131F00DF644E /* KMChromiumTabView.xib in Resources */,
 				AD1D48402AFB81F4007AC1F0 /* KMMergeBlankView.xib in Resources */,
 				BB986AE92AD5376100ADF172 /* WelcomeWindowController.xib in Resources */,
@@ -17013,6 +17026,7 @@
 				BB0A55182A3074F400B6E84B /* KMHoverView.swift in Sources */,
 				ADD56F572BB3F48300E87ED9 /* KMFreeTextStylesViewController.m in Sources */,
 				9F53D54F2AD677A000CCF9D8 /* CPDFListViewConfig.swift in Sources */,
+				9FC346552CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */,
 				AD7D5CB32B9070AF006562CD /* KMSyncDot.swift in Sources */,
 				BB2A98522B270B3300647AF3 /* KMBatchAddBackgroundOperation.swift in Sources */,
 				9F0CB4C4298625F400007028 /* NSColor+KMExtensions.swift in Sources */,
@@ -18594,6 +18608,7 @@
 				BBFA1CCE2B609E890053AD4A /* KMScreenShotMaskWindowController.swift in Sources */,
 				9F5664882988B16F00020985 /* KMTextfieldVC.swift in Sources */,
 				652E95432C6913C20061FA40 /* KMLineAndBorderItemView.swift in Sources */,
+				9FC346562CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */,
 				89D2D2FC294C806000BFF5FE /* KMPDFThumbnailItem.swift in Sources */,
 				BB3D970B2B2FEAC8007094C8 /* KMPDFRedactViewController.swift in Sources */,
 				ADDF83302B391A5C00A81A4E /* NSGeometry+PDFListView.m in Sources */,
@@ -20409,6 +20424,7 @@
 				AD867FB129DFBB1200F00440 /* KMAnnotationOutlineCellView.swift in Sources */,
 				9F1FE50129406E4700E952CA /* CTTabStripModel.m in Sources */,
 				AD055EB62B8841780035F824 /* SKSeparatorCell.m in Sources */,
+				9FC346572CD0C4FB00F35823 /* KMEnterVerificationCodeView.swift in Sources */,
 				BBF729B12B1962C900576AC5 /* KMRemoveHeaderFooterQueue.swift in Sources */,
 				BBB789AA2BE8BF2400F7E09C /* AIChatFileInfoItem.swift in Sources */,
 				AD85D1A62AF09864000F4D28 /* KMHomeQuickToolsWindowController.swift in Sources */,