From cedd50bc788977c73d803b801ba47d597e151eb3 Mon Sep 17 00:00:00 2001 From: Alexandru Lazar Date: Wed, 3 Jun 2020 10:35:15 +0300 Subject: [PATCH] Code input control improvements. --- DP3TApp.xcodeproj/project.pbxproj | 14 +- .../CodeInput/CodeSingleControl.swift | 170 +++++++++ .../CodeInput/CodeTextField.swift | 60 ++++ .../CodeInput/NSCodeInputControl.swift | 337 +++++------------- .../CodeInput/NSCodeInputViewController.swift | 49 ++- .../NSNoCodeInformationViewController.swift | 1 - 6 files changed, 369 insertions(+), 262 deletions(-) create mode 100644 DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeSingleControl.swift create mode 100644 DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeTextField.swift diff --git a/DP3TApp.xcodeproj/project.pbxproj b/DP3TApp.xcodeproj/project.pbxproj index 2516db39c..1fec3a44b 100644 --- a/DP3TApp.xcodeproj/project.pbxproj +++ b/DP3TApp.xcodeproj/project.pbxproj @@ -263,6 +263,10 @@ 8E81CCCF241FD813006F2437 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 8E81CCCE241FD813006F2437 /* SnapKit */; }; 8EB23D78245AF2C30073E83A /* RandomGenerators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EB23D77245AF2C30073E83A /* RandomGenerators.swift */; }; A6BBA110246BFCBC00E42EE7 /* UIDevice+ScreenType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6BBA10F246BFCBC00E42EE7 /* UIDevice+ScreenType.swift */; }; + A6C03418248788E100B425ED /* CodeSingleControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C03417248788E100B425ED /* CodeSingleControl.swift */; }; + A6C03419248788E100B425ED /* CodeSingleControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C03417248788E100B425ED /* CodeSingleControl.swift */; }; + A6C0341B2487890B00B425ED /* CodeTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0341A2487890B00B425ED /* CodeTextField.swift */; }; + A6C0341C2487890B00B425ED /* CodeTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0341A2487890B00B425ED /* CodeTextField.swift */; }; AACFA6A3243088A4005595E6 /* NSAnimatedGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AACFA6A2243088A4005595E6 /* NSAnimatedGraphView.swift */; }; AAF73663242F2DC90051E34A /* NSModuleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAF73662242F2DC90051E34A /* NSModuleHeaderView.swift */; }; AAF73666242F2EA00051E34A /* NSBegegnungenModuleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAF73665242F2EA00051E34A /* NSBegegnungenModuleView.swift */; }; @@ -449,6 +453,8 @@ 8E81CCB1241FCC7F006F2437 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8EB23D77245AF2C30073E83A /* RandomGenerators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomGenerators.swift; sourceTree = ""; }; A6BBA10F246BFCBC00E42EE7 /* UIDevice+ScreenType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+ScreenType.swift"; sourceTree = ""; }; + A6C03417248788E100B425ED /* CodeSingleControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeSingleControl.swift; sourceTree = ""; }; + A6C0341A2487890B00B425ED /* CodeTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeTextField.swift; sourceTree = ""; }; AACFA6A2243088A4005595E6 /* NSAnimatedGraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAnimatedGraphView.swift; sourceTree = ""; }; AAF73662242F2DC90051E34A /* NSModuleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSModuleHeaderView.swift; sourceTree = ""; }; AAF73665242F2EA00051E34A /* NSBegegnungenModuleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSBegegnungenModuleView.swift; sourceTree = ""; }; @@ -591,8 +597,10 @@ isa = PBXGroup; children = ( 6E1771532440B09A0008D73D /* NSCodeInputViewController.swift */, - 6E1771552440B5140008D73D /* NSCodeInputControl.swift */, 6EA49E2A2444410D009EFCAB /* NSNoCodeInformationViewController.swift */, + 6E1771552440B5140008D73D /* NSCodeInputControl.swift */, + A6C03417248788E100B425ED /* CodeSingleControl.swift */, + A6C0341A2487890B00B425ED /* CodeTextField.swift */, ); path = CodeInput; sourceTree = ""; @@ -1482,6 +1490,7 @@ 242D21FC245C4BD8005DAEA8 /* NSLabelType.swift in Sources */, 242D21FD245C4BD8005DAEA8 /* UBPListValue.swift in Sources */, 242D21FE245C4BD8005DAEA8 /* NSUnderlinedButton.swift in Sources */, + A6C03419248788E100B425ED /* CodeSingleControl.swift in Sources */, 242D21FF245C4BD8005DAEA8 /* AuthorizationModels.swift in Sources */, 242D2200245C4BD8005DAEA8 /* NSModuleHeaderView.swift in Sources */, 242D2201245C4BD8005DAEA8 /* NSModuleBaseView.swift in Sources */, @@ -1546,6 +1555,7 @@ 242D2238245C4BD8005DAEA8 /* NSHeaderArcView.swift in Sources */, 242D2239245C4BD8005DAEA8 /* ReportingManager.swift in Sources */, 242D223A245C4BD8005DAEA8 /* NSOnboardingContentViewController.swift in Sources */, + A6C0341C2487890B00B425ED /* CodeTextField.swift in Sources */, 242D223B245C4BD8005DAEA8 /* NSHeaderErrorView.swift in Sources */, 242D223C245C4BD8005DAEA8 /* NSInformBottomButtonViewController.swift in Sources */, 242D223D245C4BD8005DAEA8 /* NSDebugscreenViewController.swift in Sources */, @@ -1614,6 +1624,7 @@ DCA3FFB424502D370003F5AD /* NSTracingErrorView.swift in Sources */, 6E7C0D1E242CE02D0017C4F9 /* NSLabelType.swift in Sources */, DC702B0B243F6FAE0066C773 /* UBPListValue.swift in Sources */, + A6C03418248788E100B425ED /* CodeSingleControl.swift in Sources */, DCA3FFB6245048A50003F5AD /* NSUnderlinedButton.swift in Sources */, 242D227D245D6581005DAEA8 /* Endpoint.swift in Sources */, 2462BA152451FD150046906D /* AuthorizationModels.swift in Sources */, @@ -1678,6 +1689,7 @@ 2443947B2445F062003ED582 /* NSHeaderArcView.swift in Sources */, 2462BA1B24521CE70046906D /* ReportingManager.swift in Sources */, DC175E402430C4C700BD2AD6 /* NSOnboardingContentViewController.swift in Sources */, + A6C0341B2487890B00B425ED /* CodeTextField.swift in Sources */, DC746D582451D50B009426B1 /* NSHeaderErrorView.swift in Sources */, 24780B30242F3EAF003BB26C /* NSInformBottomButtonViewController.swift in Sources */, 6E3F65F72449B61A00980A4E /* NSDebugscreenViewController.swift in Sources */, diff --git a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeSingleControl.swift b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeSingleControl.swift new file mode 100644 index 000000000..e65e909bf --- /dev/null +++ b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeSingleControl.swift @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2020 Ubique Innovation AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +import UIKit + +protocol CodeSingleControlDelegate: class { + func fillFieldsWith(_ text: String, for startControl: CodeSingleControl) + func change(_ control: CodeSingleControl) + func shouldJumpToNextField() + func shouldJumpToPreviousField() + func shouldCheckSendAllowed() +} + +class CodeSingleControl: UIView { + weak var delegate: CodeSingleControlDelegate? + fileprivate let textField = CodeTextField() + private let emptyCharacter = "\u{200B}" + + private var hadText: Bool = false + fileprivate var accessibilityIndex: Int + + init(accessibilityIndex: Int) { + self.accessibilityIndex = accessibilityIndex + super.init(frame: .zero) + setup() + + textField.text = UIAccessibility.isVoiceOverRunning ? "" : emptyCharacter + textField.accessibilityTraits = .staticText + accessibilityTraits = .staticText + isAccessibilityElement = true + } + + override func accessibilityElementDidBecomeFocused() { + textField.becomeFirstResponder() + } + + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Checks/Code + + public func characterIsSet() -> Bool { + (textField.text ?? "").replacingOccurrences(of: emptyCharacter, with: "").count > 0 + } + + public func character() -> String? { + textField.text?.replacingOccurrences(of: emptyCharacter, with: "") + } + + public func clearInput() { + textField.resignFirstResponder() + textField.text = emptyCharacter + } + + // MARK: - Copy&paste + + public func setDigit(digit: String) { + textField.text = digit + } + + // MARK: - First responder + + override func becomeFirstResponder() -> Bool { + changeBorderStyle(isSelected: true) + return textField.becomeFirstResponder() + } + + override func resignFirstResponder() -> Bool { + changeBorderStyle(isSelected: false) + return textField.resignFirstResponder() + } + + func reset() { + textField.text = emptyCharacter + hadText = false + } + + private func changeBorderStyle(isSelected: Bool) { + backgroundColor = UIColor.ns_backgroundSecondary + + if isSelected { + layer.borderWidth = 2.0 + layer.borderColor = UIColor.ns_purple.cgColor + } else { + layer.borderWidth = 1.0 + layer.borderColor = UIColor(ub_hexString: "#e5e5e5")?.cgColor + } + } + + // MARK: - Setup + + private func setup() { + snp.makeConstraints { make in + make.height.equalTo(36) + } + + addSubview(textField) + + textField.snp.makeConstraints { make in + make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: -2, bottom: 0, right: -2)) + } + + changeBorderStyle(isSelected: false) + + textField.font = NSLabelType.title.font + textField.textAlignment = .center + textField.textColor = .ns_text + textField.keyboardType = .numberPad + + textField.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged) + textField.delegate = self + textField.codeTextFieldDelegate = self + } + + @objc private func editingChanged(sender: UITextField) { + if let text = sender.text, text.count >= 1 { + sender.text = String(text.dropFirst(text.count - 1)) + hadText = true + delegate?.shouldJumpToNextField() + } else if let text = sender.text, text.count == 0 { + sender.text = emptyCharacter + if !hadText { + delegate?.shouldJumpToPreviousField() + } else { + delegate?.shouldCheckSendAllowed() + } + + hadText = false + } + } +} + +// MARK: - UITextFieldDelegate + +extension CodeSingleControl: UITextFieldDelegate { + + func textField(_: UITextField, shouldChangeCharactersIn _: NSRange, replacementString string: String) -> Bool { + return string != " " + } + + func textFieldDidBeginEditing(_: UITextField) { + delegate?.change(self) + changeBorderStyle(isSelected: true) + } + + func textFieldDidEndEditing(_: UITextField) { + changeBorderStyle(isSelected: false) + } +} + +// MARK: - CodeTextFieldDelegate + +extension CodeSingleControl: CodeTextFieldDelegate { + + func fillWith(_ text: String) { + delegate?.fillFieldsWith(text, for: self) + } + + func getAccessibilityIndexIndex() -> Int { + return accessibilityIndex + } +} diff --git a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeTextField.swift b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeTextField.swift new file mode 100644 index 000000000..16dd8b38b --- /dev/null +++ b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/CodeTextField.swift @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Ubique Innovation AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ + +import UIKit + +protocol CodeTextFieldDelegate: class { + func fillWith(_ text: String) + func getAccessibilityIndexIndex() -> Int +} + +class CodeTextField: UITextField { + + weak var codeTextFieldDelegate: CodeTextFieldDelegate? + + override func paste(_: Any?) { + let pasteboard = UIPasteboard.general + + if let text = pasteboard.string { + codeTextFieldDelegate?.fillWith(text) + } + } + + override func canPerformAction(_ action: Selector, withSender _: Any?) -> Bool { + return action == #selector(UIResponderStandardEditActions.paste) + } + + override var accessibilityLabel: String? { + get { + + guard let accessibilityIndex = codeTextFieldDelegate?.getAccessibilityIndexIndex() else { + return "" + } + + if let text = text, !text.isEmpty { + return "accessibility_\(accessibilityIndex)nd".ub_localized + "accessibility_code_input_textfield".ub_localized + } else { + return "accessibility_\(accessibilityIndex)nd".ub_localized + "accessibility_code_input_textfield_empty".ub_localized + } + } + set { + super.accessibilityLabel = newValue + } + } + + override var accessibilityHint: String? { + get { + return "accessibility_code_input_hint".ub_localized + } + set { + super.accessibilityHint = newValue + } + } +} diff --git a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputControl.swift b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputControl.swift index dd7e10d06..662c87e2f 100644 --- a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputControl.swift +++ b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputControl.swift @@ -8,345 +8,194 @@ * SPDX-License-Identifier: MPL-2.0 */ -import Foundation import UIKit -protocol NSCodeControlProtocol { - func changeSendPermission(to sendAllowed: Bool) +protocol NSCodeControlDelegate: class { + func didChangeSendPermission(to sendAllowed: Bool) func lastInputControlEntered() + func didEnterAnInvalidCode() } class NSCodeControl: UIView { - public var controller: NSCodeControlProtocol? - + public weak var delegate: NSCodeControlDelegate? + // MARK: - Input number - private let numberOfInputs = 12 - private var controls: [NSCodeSingleControl] = [] - private var currentControl: NSCodeSingleControl? - + private var controls: [CodeSingleControl] = [] + private var currentControl: CodeSingleControl? + private let stackView = UIStackView() - - private var currentIndex = 0 - + // MARK: - Init - + init() { super.init(frame: .zero) setup() } - + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } - + // MARK: - Public functions - + public func code() -> String { var code = "" - + for control in controls { - if let c = control.code() { - code.append(contentsOf: c) + if let character = control.character() { + code.append(contentsOf: character) } } - + return code } - + public func clearAndRestart() { for control in controls { control.clearInput() } - + currentControl = nil if !UIAccessibility.isVoiceOverRunning { jumpToNextField() } } - + // MARK: - Setup - + private func setup() { var elements = [Any]() addSubview(stackView) - + stackView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() make.left.right.equalToSuperview() } - + stackView.distribution = .fillEqually stackView.spacing = 1.0 - - for i in 0 ..< numberOfInputs { - let singleControl = NSCodeSingleControl(index: i) - singleControl.parent = self - + + for index in 0 ..< numberOfInputs { + let singleControl = CodeSingleControl(accessibilityIndex: index + 1) + singleControl.delegate = self controls.append(singleControl) stackView.addArrangedView(singleControl) elements.append(singleControl.textField) - if (i + 1) % 3 == 0, i + 1 != numberOfInputs { + if (index + 1) % 3 == 0, index + 1 != numberOfInputs { stackView.setCustomSpacing(NSPadding.small + 2.0, after: singleControl) } } - + accessibilityElements = elements } - + // MARK: - Control - + public func jumpToNextField() { - if let c = currentControl, let i = controls.firstIndex(of: c) { - if i + 1 < numberOfInputs { - _ = controls[i + 1].becomeFirstResponder() - currentControl = controls[i + 1] + if let currentControl = currentControl, let indexOfControl = controls.firstIndex(of: currentControl) { + if indexOfControl + 1 < numberOfInputs { + _ = controls[indexOfControl + 1].becomeFirstResponder() + self.currentControl = controls[indexOfControl + 1] } else { - controller?.lastInputControlEntered() + delegate?.lastInputControlEntered() } } else { - _ = controls[0].becomeFirstResponder() - currentControl = controls[0] + _ = controls.first?.becomeFirstResponder() + currentControl = controls.first } - + checkSendAllowed() } - + public func jumpToPreviousField() { - if let c = currentControl, let i = controls.firstIndex(of: c) { - if i > 0 { - _ = controls[i - 1].becomeFirstResponder() - controls[i - 1].reset() - currentControl = controls[i - 1] + if let currentControl = currentControl, let index = controls.firstIndex(of: currentControl) { + if index > 0 { + _ = controls[index - 1].becomeFirstResponder() + controls[index - 1].reset() + self.currentControl = controls[index - 1] } } else { - _ = controls[0].becomeFirstResponder() - currentControl = controls[0] + _ = controls.first?.becomeFirstResponder() + currentControl = controls.first } - + checkSendAllowed() } - - public func changeControl(control: NSCodeSingleControl) { + + public func changeControl(control: CodeSingleControl) { currentControl = control } - + override func resignFirstResponder() -> Bool { currentControl?.resignFirstResponder() ?? false } - + // MARK: - Protocol - + public func checkSendAllowed() { - for c in controls { - if !c.codeIsSet() { - controller?.changeSendPermission(to: false) + for control in controls { + if !control.characterIsSet() { + delegate?.didChangeSendPermission(to: false) return } } - - controller?.changeSendPermission(to: true) + + delegate?.didChangeSendPermission(to: true) } - + // MARK: - Copy & paste - - public func fill(text: String, startControl: NSCodeSingleControl) { + + public func fill(text: String, startControl: CodeSingleControl) { var started = false - + var onlyDigits = text.filter { Int("\($0)") != nil } - - for c in controls { - if c == startControl { + + // User copy pastes a wrong covid code that contains something other than digits + if onlyDigits != text { + delegate?.didEnterAnInvalidCode() + return + } + + for control in controls { + if control == startControl { started = true } - + if let first = onlyDigits.first, started { - c.setDigit(digit: String(first)) + control.setDigit(digit: String(first)) onlyDigits.removeFirst() - _ = c.becomeFirstResponder() + _ = control.becomeFirstResponder() } } - + jumpToNextField() - + checkSendAllowed() } } -class NSCodeSingleControl: UIView, UITextFieldDelegate { - public weak var parent: NSCodeControl? - - public let textField = NSTextField() - private let emptyCharacter = "\u{200B}" - - private var hadText: Bool = false - public var indexInCodeControl: Int - - init(index: Int) { - indexInCodeControl = index - super.init(frame: .zero) - setup() +// MARK: - CodeSingleControlDelegate - textField.text = UIAccessibility.isVoiceOverRunning ? "" : emptyCharacter - textField.accessibilityTraits = .staticText - accessibilityTraits = .staticText - isAccessibilityElement = true +extension NSCodeControl: CodeSingleControlDelegate { + + func fillFieldsWith(_ text: String, for startControl: CodeSingleControl) { + fill(text: text, startControl: startControl) } - - override func accessibilityElementDidBecomeFocused() { - textField.becomeFirstResponder() - } - - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Checks/Code - - public func codeIsSet() -> Bool { - (textField.text ?? "").replacingOccurrences(of: emptyCharacter, with: "").count > 0 - } - - public func code() -> String? { - textField.text?.replacingOccurrences(of: emptyCharacter, with: "") + + func change(_ control: CodeSingleControl) { + changeControl(control: control) } - - public func clearInput() { - textField.resignFirstResponder() - textField.text = emptyCharacter - } - - // MARK: - Copy&paste - - public func fill(text: String) { - parent?.fill(text: text, startControl: self) - } - - public func setDigit(digit: String) { - textField.text = digit - } - - // MARK: - First responder - - override func becomeFirstResponder() -> Bool { - changeBorderStyle(isSelected: true) - return textField.becomeFirstResponder() - } - - override func resignFirstResponder() -> Bool { - changeBorderStyle(isSelected: false) - return textField.resignFirstResponder() - } - - func reset() { - textField.text = emptyCharacter - hadText = false - } - - private func changeBorderStyle(isSelected: Bool) { - backgroundColor = UIColor.ns_backgroundSecondary - - if isSelected { - layer.borderWidth = 2.0 - layer.borderColor = UIColor.ns_purple.cgColor - } else { - layer.borderWidth = 1.0 - layer.borderColor = UIColor(ub_hexString: "#e5e5e5")?.cgColor - } - } - - // MARK: - Setup - - private func setup() { - snp.makeConstraints { make in - make.height.equalTo(36) - } - - addSubview(textField) - - textField.snp.makeConstraints { make in - make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: -2, bottom: 0, right: -2)) - } - - changeBorderStyle(isSelected: false) - - textField.font = NSLabelType.title.font - textField.textAlignment = .center - textField.textColor = .ns_text - textField.keyboardType = .numberPad - - textField.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged) - textField.delegate = self - textField.singleControl = self - } - - // MARK: - Textfield Delegate - - func textField(_: UITextField, shouldChangeCharactersIn _: NSRange, replacementString string: String) -> Bool { - return string != " " - } - - @objc private func editingChanged(sender: UITextField) { - if let text = sender.text, text.count >= 1 { - sender.text = String(text.dropFirst(text.count - 1)) - hadText = true - parent?.jumpToNextField() - } else if let text = sender.text, text.count == 0 { - sender.text = emptyCharacter - if !hadText { - parent?.jumpToPreviousField() - } else { - parent?.checkSendAllowed() - } - - hadText = false - } - } - - func textFieldDidBeginEditing(_: UITextField) { - parent?.changeControl(control: self) - changeBorderStyle(isSelected: true) - } - - func textFieldDidEndEditing(_: UITextField) { - changeBorderStyle(isSelected: false) - } -} - -class NSTextField: UITextField { - public weak var singleControl: NSCodeSingleControl? - - override func paste(_: Any?) { - let pasteboard = UIPasteboard.general - - if let text = pasteboard.string { - singleControl?.fill(text: text) - } - } - - override func canPerformAction(_ action: Selector, withSender _: Any?) -> Bool { - return action == #selector(UIResponderStandardEditActions.paste) + + func shouldCheckSendAllowed() { + checkSendAllowed() } - - override var accessibilityLabel: String? { - get { - if let text = text, !text.isEmpty { - return (singleControl == nil ? "" : "accessibility_\(singleControl!.indexInCodeControl + 1)nd".ub_localized) + "accessibility_code_input_textfield".ub_localized - } else { - return (singleControl == nil ? "" : "accessibility_\(singleControl!.indexInCodeControl + 1)nd".ub_localized) + "accessibility_code_input_textfield_empty".ub_localized - } - } - set { - super.accessibilityLabel = newValue - } + + func shouldJumpToPreviousField() { + jumpToPreviousField() } - - override var accessibilityHint: String? { - get { - return "accessibility_code_input_hint".ub_localized - } - set { - super.accessibilityHint = newValue - } + + func shouldJumpToNextField() { + jumpToNextField() } } diff --git a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputViewController.swift b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputViewController.swift index 8a36968cd..8bf265ef1 100644 --- a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputViewController.swift +++ b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSCodeInputViewController.swift @@ -8,10 +8,9 @@ * SPDX-License-Identifier: MPL-2.0 */ -import Foundation import UIKit -class NSCodeInputViewController: NSInformStepViewController, NSCodeControlProtocol { +class NSCodeInputViewController: NSInformStepViewController { // MARK: - Views let stackScrollView = NSStackScrollView(axis: .vertical, spacing: 0) @@ -88,7 +87,7 @@ class NSCodeInputViewController: NSInformStepViewController, NSCodeControlProtoc make.left.right.equalToSuperview() } - codeControl.controller = self + codeControl.delegate = self stackScrollView.addArrangedView(codeControlContainer) stackScrollView.addSpacerView(NSPadding.medium * 4.0) @@ -175,19 +174,6 @@ class NSCodeInputViewController: NSInformStepViewController, NSCodeControlProtoc navigationController?.pushViewController(NSNoCodeInformationViewController(), animated: true) } - // MARK: - NSCodeControlProtocol - - func changeSendPermission(to sendAllowed: Bool) { - sendButton.isEnabled = sendAllowed - updateAccessibilityLabelOfButton(sendAllowed: sendAllowed) - } - - func lastInputControlEntered() { - if UIAccessibility.isVoiceOverRunning { - UIAccessibility.post(notification: .screenChanged, argument: sendButton) - } - } - private func updateAccessibilityLabelOfButton(sendAllowed: Bool) { let codeEingabe = "accessibility_code_button_current_code_hint".ub_localized + codeControl.code() if sendAllowed { @@ -201,3 +187,34 @@ class NSCodeInputViewController: NSInformStepViewController, NSCodeControlProtoc } } } + +// MARK: - NSCodeControlDelegate + +extension NSCodeInputViewController: NSCodeControlDelegate { + + func didChangeSendPermission(to sendAllowed: Bool) { + sendButton.isEnabled = sendAllowed + updateAccessibilityLabelOfButton(sendAllowed: sendAllowed) + } + + func lastInputControlEntered() { + if UIAccessibility.isVoiceOverRunning { + UIAccessibility.post(notification: .screenChanged, argument: sendButton) + } + } + + func didEnterAnInvalidCode() { + self.codeControl.clearAndRestart() + self.errorView.isHidden = false + self.textLabel.isHidden = true + + self.stopLoading() + if UIAccessibility.isVoiceOverRunning { + UIAccessibility.post(notification: .screenChanged, argument: self.errorTitleLabel) + } + + self.navigationItem.hidesBackButton = false + self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true + self.navigationItem.rightBarButtonItem = self.rightBarButtonItem + } +} diff --git a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSNoCodeInformationViewController.swift b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSNoCodeInformationViewController.swift index 3a342d455..c93d65c45 100644 --- a/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSNoCodeInformationViewController.swift +++ b/DP3TApp/Screens/Homescreen/InformBroadcast/CodeInput/NSNoCodeInformationViewController.swift @@ -8,7 +8,6 @@ * SPDX-License-Identifier: MPL-2.0 */ -import Foundation import UIKit class NSNoCodeInformationViewController: NSInformStepViewController {