Files
2021-12-22 12:14:16 +03:00

175 lines
5.6 KiB
Swift

//
// UnderlineTextField.swift
// PrivadoVPN
//
// Created by Juraldinio on 1/21/21.
// Copyright © 2021 Privado LLC. All rights reserved.
//
import Foundation
import AppKit
final class UnderlineTextField: NSTextField, NSTextFieldDelegate {
enum Constants {
static let lineHeight: CGFloat = 2.0
enum Font {
static let name = PrivadoConstants.Font.regular
static let size: CGFloat = 14.0
}
enum Color {
static let text = NSColor.white
static let placeholder = NSColor(calibratedRed: 173.0 / 255, green: 179.0 / 255, blue: 210.0 / 255, alpha: 1.0)
static let neutral = NSColor(calibratedRed: 45.0 / 255, green: 51.0 / 255, blue: 82.0 / 255, alpha: 1.0)
static let beginEditing = NSColor(red: 40, green: 215, blue: 153)
}
}
// MARK: - Properties
private let bottomLineView: NSView
var coloredPlaceHolder: String? {
get {
return self.placeholderAttributedString?.string
}
set {
if let value = newValue {
let attrs = [NSAttributedString.Key.foregroundColor: Constants.Color.placeholder,
NSAttributedString.Key.font: NSFont(name: Constants.Font.name, size: Constants.Font.size)]
self.placeholderAttributedString = NSAttributedString(string: value, attributes: attrs)
} else {
self.placeholderAttributedString = nil
}
}
}
func hightlight(with color: NSColor?) {
self.bottomLineView.viewBackgroundColor = color ?? Constants.Color.neutral
}
// MARK: - Initializers
override init(frame frameRect: NSRect) {
self.bottomLineView = NSView()
super.init(frame: frameRect)
self.cell?.isScrollable = true
self.setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Private
private func setupUI() {
self.isBezeled = false
self.drawsBackground = false
self.translatesAutoresizingMaskIntoConstraints = false
self.focusRingType = .none
self.usesSingleLineMode = true
self.textColor = Constants.Color.text
self.delegate = self
self.font = NSFont(name: Constants.Font.name, size: Constants.Font.size)
self.bottomLineView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.bottomLineView)
NSLayoutConstraint.activate([
self.bottomLineView.heightAnchor.constraint(equalToConstant: Constants.lineHeight),
self.bottomLineView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.bottomLineView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
self.bottomLineView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
])
self.hightlight(with: nil)
}
private func performEditingKeyEquivalent(with event: NSEvent) -> Bool {
guard event.type == NSEvent.EventType.keyDown else { return false }
let commandKey = NSEvent.ModifierFlags.command.rawValue
let commandShiftKey = NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue
let key = event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue
switch key {
case commandKey: return self.handleCommandKey(keyCode: event.keyCode)
case commandShiftKey: return self.handleShiftKey(keyCode: event.keyCode)
default:
break
}
return false
}
private func handleCommandKey(keyCode: UInt16) -> Bool {
switch keyCode {
case KeyCode.x:
if NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self) { return true }
case KeyCode.c:
if NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self) { return true }
case KeyCode.v:
if NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self) { return true }
case KeyCode.z:
if NSApp.sendAction(Selector(("undo:")), to: nil, from: self) { return true }
case KeyCode.a:
if NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self) { return true }
default:
break
}
return false
}
private func handleShiftKey(keyCode: UInt16) -> Bool {
if keyCode == KeyCode.z {
if NSApp.sendAction(Selector(("redo:")), to: nil, from: self) { return true }
}
return false
}
// MARK: - Lifecycle
// Show edit pointer
override func viewDidMoveToWindow() {
if let textView = self.window?.fieldEditor(true, for: self) as? NSTextView {
textView.insertionPointColor = Constants.Color.text
textView.alignment = .center
}
}
// Allow hotkeys in field
override func performKeyEquivalent(with event: NSEvent) -> Bool {
if self.performEditingKeyEquivalent(with: event) {
return true
}
return super.performKeyEquivalent(with: event)
}
// MARK: - NSTextFieldDelegate
func controlTextDidChange(_ obj: Notification) {
// self.hightlight(with: nil)
}
func controlTextDidBeginEditing(_ obj: Notification) {
self.hightlight(with: Constants.Color.beginEditing)
}
func controlTextDidEndEditing(_ obj: Notification) {
self.hightlight(with: nil)
}
}