// _____ _ // |_ _| |_ _ _ ___ ___ _ __ __ _ // | | | ' \| '_/ -_) -_) ' \/ _` |_ // |_| |_||_|_| \___\___|_|_|_\__,_(_) // // Threema iOS Client // Copyright (c) 2018-2020 Threema GmbH // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License, version 3, // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import UIKit @objc protocol SetupTextFieldDelegate { func editingChangedTextField(_ sender: SetupTextField, forEvent event: UIEvent) -> Void func primaryActionTriggered(_ sender: SetupTextField, forEvent event: UIEvent) -> Void } @IBDesignable class SetupTextField: UIView { private var currentDefaultText: String? //MARK: Control Properties @IBInspectable var showIcon: UIImage? { didSet { self.icon.image = showIcon?.withTint(Colors.white()) self.icon.isHidden = false self.textBackground.frame = CGRect(x: 40, y: 0, width: self.frame.width - 40, height: self.frame.height) self.textField.frame = CGRect(x: 45, y: 5, width: 230, height: 30) } } @IBInspectable var placeholder: String? { didSet { let foregroundColor = [NSAttributedString.Key.foregroundColor: UIColor.lightGray] //THREEMA_COLOR_PLACEHOLDER self.textField.attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: foregroundColor) self.textField.accessibilityLabel = placeholder } } @IBInspectable var defaultText: String? { didSet { self.currentDefaultText = defaultText } } @IBInspectable var capitalization: Int = 0 { didSet { if let type = UITextAutocapitalizationType(rawValue: capitalization) { self.textField.autocapitalizationType = type } } } @IBInspectable var keyboardType: Int = 0 { didSet { if let type = UIKeyboardType(rawValue: keyboardType) { self.textField.keyboardType = type } } } @IBInspectable var returnKey: Int = 0 { didSet { if let type = UIReturnKeyType(rawValue: returnKey) { self.textField.returnKeyType = type } } } @IBInspectable var secureTextEntry: Bool = false { didSet { self.textField.isSecureTextEntry = secureTextEntry } } var text: String? { get { return self.textField.text } set { self.textField.text = newValue } } override var isFirstResponder: Bool { get { return self.textField.isFirstResponder } } //MARK: delegate control events weak var delegate: SetupTextFieldDelegate? @objc func editingChanged(_ sender: UITextField, forEvent event: UIEvent) { self.delegate?.editingChangedTextField(self, forEvent: event) } @objc private func touchDown(_ sender: UITextField, forEvent event: UIEvent) { guard let current = self.currentDefaultText, let currentText = sender.text, currentText.count == 0 else { return } sender.text = current } @objc private func primaryActionTriggered(_ sender: UITextField, forEvent event: UIEvent) { self.delegate?.primaryActionTriggered(self, forEvent: event) } //MARK: Initialization override init(frame: CGRect) { super.init(frame: frame) self.setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.setup() } @discardableResult override func becomeFirstResponder() -> Bool { return self.textField.becomeFirstResponder() } @discardableResult override func resignFirstResponder() -> Bool { return self.textField.resignFirstResponder() } private let icon: UIImageView = { let icon = UIImageView() icon.isHidden = true icon.frame = CGRect(x: 11, y: 11, width: 18, height: 18) return icon }() private let textBackground: UIView = { let background = UIView() background.alpha = 0.1 background.backgroundColor = .white background.layer.borderWidth = 0.5 background.layer.borderColor = UIColor(red:1.0, green:1.0, blue:1.0, alpha:0.1).cgColor background.layer.cornerRadius = 3 return background }() private let textField: UITextField = { let field = UITextField() field.textColor = UIColor.white field.tintColor = UIColor.white field.backgroundColor = .clear field.borderStyle = .none field.textAlignment = .left field.font = UIFont.systemFont(ofSize: 16.0, weight: .light) field.autocorrectionType = UITextAutocorrectionType.no field.spellCheckingType = UITextSpellCheckingType.no field.keyboardAppearance = UIKeyboardAppearance.dark return field }() //MARK: Private Methods private func setup() { self.backgroundColor = UIColor.clear let background = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)) background.backgroundColor = UIColor.clear background.layer.borderWidth = 0.5 background.layer.borderColor = UIColor(red:1.0, green:1.0, blue:1.0, alpha:0.1).cgColor background.layer.cornerRadius = 3 self.textBackground.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height) self.textField.frame = CGRect(x: 5, y: 5, width: 270, height: 30) self.textField.addTarget(self, action: #selector(editingChanged), for: .editingChanged) self.textField.addTarget(self, action: #selector(touchDown), for: .touchDown) self.textField.addTarget(self, action: #selector(primaryActionTriggered), for: .primaryActionTriggered) self.textField.delegate = self self.textField.tintColor = Colors.mainThemeDark() self.addSubview(background) self.addSubview(self.icon) self.addSubview(textBackground) self.addSubview(self.textField) } } extension SetupTextField: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Check if it has lowercase characters if self.capitalization != 0 && string.rangeOfCharacter(from: CharacterSet.lowercaseLetters) != nil { if let textCurrent = textField.text, let rangeCurrent = Range(range, in: textCurrent) { // Get current cursor position let selectedTextRangeCurrent = textField.selectedTextRange // Replace lowercase character with uppercase character textField.text = textField.text?.replacingCharacters(in: rangeCurrent, with: string.uppercased()) if let selectedTextRangeCurrent = selectedTextRangeCurrent { // Set current cursor position, if cursor position + 1 is valid if let newPosition = textField.position(from: selectedTextRangeCurrent.start, offset: 1) { textField.selectedTextRange = textField.textRange(from: newPosition, to: newPosition) } } } return false } return true; } }