123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- //
- // KMSecureTextFiled.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2022/11/28.
- //
- import Cocoa
- enum KMSecureTextFiledMode: Int {
- case ciphertext = 0 /// 密文
- case plaintext = 1 /// 明文
- }
- enum KMSecureTextFiledViewMode: Int {
- case never = 0
- case whileEditing
- case unlessEditing
- case always
- }
- typealias KMSecureTextFiledFirstResponderHandler = (Bool)->()
- private class KMSecureTextFiled_TextFiled: NSTextField {
-
- var firstResponderHandler: KMSecureTextFiledFirstResponderHandler?
-
- override func becomeFirstResponder() -> Bool {
- let result = super.becomeFirstResponder()
-
- guard let callback = firstResponderHandler else {
- return result
- }
- callback(result)
-
- return result
- }
- }
- private class KMSecureTextFiled_SecureTextFiled: NSSecureTextField {
-
- var firstResponderHandler: KMSecureTextFiledFirstResponderHandler?
-
- override func becomeFirstResponder() -> Bool {
- let result = super.becomeFirstResponder()
-
- guard let callback = firstResponderHandler else {
- return result
- }
- callback(result)
-
- return result
- }
- }
- typealias KMSecureTextFiledValueDidChange = (_ view: KMSecureTextFiled, _ string: String) -> Void
- typealias KMSecureTextFiledBecomeFirstResponderHandler = (NSView)->()
- typealias KMSecureTextFiledEnterAction = () -> ()
- class KMSecureTextFiled: NSView {
- var enterAction: KMSecureTextFiledEnterAction?
-
- var backgroundView = NSView()
- private var textFiled = KMSecureTextFiled_TextFiled()
- private var secureTextField = KMSecureTextFiled_SecureTextFiled()
-
- var mode: KMSecureTextFiledMode = .ciphertext
- private var _rightView: NSView?
- var rightView: NSView? {
- get {
- return self._rightView
- }
- set {
- if self._rightView != newValue {
- if let view = self._rightView {
- view.removeFromSuperview()
- }
-
- self._rightView = newValue
- }
-
- if let view = self._rightView {
- self.addSubview(view)
- self.layoutSubtreeIfNeeded()
- }
-
- self.updateRightViewStateIfNeed(editing: self.kmEnabled)
- }
- }
- private var _rightViewMode = KMSecureTextFiledViewMode.whileEditing
- var rightViewMode: KMSecureTextFiledViewMode {
- get {
- return self._rightViewMode
- }
- set {
- self._rightViewMode = newValue
-
- self.updateRightViewStateIfNeed(editing: self.kmEnabled)
- }
- }
-
- private var _enabled = true
- var kmEnabled: Bool {
- get {
- return self._enabled
- }
- set {
- self._enabled = newValue
-
- textFiled.isEnabled = newValue
- secureTextField.isEnabled = newValue
-
- self.updateRightViewStateIfNeed(editing: newValue)
- }
- }
-
- var placeholderString: String {
- get {
- if (self.mode == .plaintext) {
- return self.textFiled.placeholderString ?? ""
- } else {
- return self.secureTextField.placeholderString ?? ""
- }
- }
- set {
- if (self.mode == .plaintext) {
- self.textFiled.placeholderString = newValue
- } else {
- self.secureTextField.placeholderString = newValue
- }
- }
- }
-
- var valueDidChange: KMSecureTextFiledValueDidChange?
- var becomeFirstResponderHandler: KMSecureTextFiledBecomeFirstResponderHandler?
- var didEndEditHandler: ((String?)->())?
-
- override init(frame frameRect: NSRect) {
- super.init(frame: frameRect)
-
- initDefaultValue()
- initSubViews()
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- }
-
- override func awakeFromNib() {
- super.awakeFromNib()
-
- initDefaultValue()
- initSubViews()
- }
-
- func initDefaultValue() {
- mode = .ciphertext
- self.secureTextField.isHidden = false
- self.secureTextField.isBezeled = false
- self.secureTextField.focusRingType = .none
- self.secureTextField.delegate = self
- self.textFiled.isHidden = true
- self.textFiled.isBezeled = false
- self.textFiled.focusRingType = .none
- self.textFiled.delegate = self
-
- let cell = self.textFiled.cell as? NSTextFieldCell
- cell?.allowedInputSourceLocales = [NSAllRomanInputSourcesLocaleIdentifier]
-
- self.textFiled.firstResponderHandler = { [unowned self] result in
- self.updateRightViewStateIfNeed(editing: result)
-
- guard let callback = self.becomeFirstResponderHandler else {
- return
- }
- callback(self)
- }
-
- self.secureTextField.firstResponderHandler = { [unowned self] result in
- self.updateRightViewStateIfNeed(editing: result)
-
- guard let callback = self.becomeFirstResponderHandler else {
- return
- }
- callback(self)
- }
- }
-
- func initSubViews() {
- self.addSubview(self.backgroundView)
- self.addSubview(self.secureTextField)
- self.addSubview(self.textFiled)
- }
-
- override func layout() {
- super.layout()
-
- let width: CGFloat = NSWidth(self.bounds)
- let height: CGFloat = NSHeight(self.bounds)
-
- self.backgroundView.frame = self.bounds
-
- var textFieldHeight: CGFloat = 22
- if let font = self.textFiled.font {
- textFieldHeight = font.pointSize * 1.5
- }
- let textFieldX: CGFloat = 12
- if let rightView = self.rightView {
- let rightWidth = NSWidth(rightView.frame)
- rightView.frame = NSMakeRect(width-rightWidth, 0, rightWidth, height)
-
- let textFieldFrame = NSMakeRect(textFieldX, (height-textFieldHeight)*0.5, width-textFieldX*2-rightWidth-5, textFieldHeight)
- self.secureTextField.frame = textFieldFrame
- self.textFiled.frame = textFieldFrame
- } else {
- let textFieldFrame = NSMakeRect(textFieldX, (height-textFieldHeight)*0.5, width-textFieldX*2, textFieldHeight)
- self.secureTextField.frame = textFieldFrame
- self.textFiled.frame = textFieldFrame
- }
- }
-
- func switchMode(mode: KMSecureTextFiledMode) {
- self.mode = mode
-
- if (mode == .ciphertext) { /// 密文
- self.secureTextField.isHidden = false
- self.secureTextField.stringValue = self.textFiled.stringValue
- self.window?.makeFirstResponder(self.secureTextField)
-
- self.textFiled.isHidden = true
- } else { /// 明文
- self.textFiled.isHidden = false
- self.textFiled.stringValue = self.secureTextField.stringValue
- self.window?.makeFirstResponder(self.textFiled)
-
- self.secureTextField.isHidden = true
- }
- }
-
- func clear() {
- self.secureTextField.stringValue = ""
- self.textFiled.stringValue = ""
-
- guard let callback = valueDidChange else {
- return
- }
-
- callback(self, "")
- }
-
- func password() -> String {
- return self.mode == .ciphertext ? self.secureTextField.stringValue : self.textFiled.stringValue
- }
-
- override func becomeFirstResponder() -> Bool {
- self.window?.makeFirstResponder(self.mode == .ciphertext ? self.secureTextField : self.textFiled)
-
- return super.becomeFirstResponder()
- }
-
- internal func updateRightViewStateIfNeed(editing: Bool) {
- guard let view = self.rightView else {
- return
- }
-
- if (self.rightViewMode == .always) {
- view.isHidden = false
- return
- }
- if (self.rightViewMode == .never) {
- view.isHidden = true
- return
- }
-
- if (editing) { // 开始编辑
- view.isHidden = self.rightViewMode != .whileEditing
- } else { // 结束编辑
- view.isHidden = self.rightViewMode == .whileEditing
- }
- }
- }
- extension KMSecureTextFiled: NSTextFieldDelegate {
- func controlTextDidChange(_ obj: Notification) {
- if (self.mode == .ciphertext) {
- if (self.secureTextField.isEqual(to: obj.object)) {
- guard let callback = valueDidChange else {
- return
- }
-
- callback(self, self.secureTextField.stringValue)
- }
- } else {
- if (self.textFiled.isEqual(to: obj.object)) {
- guard let callback = valueDidChange else {
- return
- }
-
- callback(self, self.secureTextField.stringValue)
- }
- }
- }
-
- func controlTextDidEndEditing(_ obj: Notification) {
- if (!self.secureTextField.isEqual(to: obj.object) && !self.textFiled.isEqual(to: obj.object)) {
- return
- }
-
- self.updateRightViewStateIfNeed(editing: false)
-
- guard let callback = self.didEndEditHandler else {
- return
- }
- callback(self.password())
- }
-
- func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
- switch commandSelector {
- case #selector(NSResponder.insertNewline(_:)):
- if let inputView = control as? NSTextField {
- // //当当前TextField按下enter
- if inputView == self.textFiled ||
- inputView == self.secureTextField {
- guard let callBack = enterAction else { return false}
-
- callBack()
- }
- }
- return true
- default:
- return false
- }
- }
- }
|