From 30b464733b56d893fce3dbc19ac562bae4756f55 Mon Sep 17 00:00:00 2001 From: babaevmm Date: Thu, 13 Mar 2025 12:15:13 +0300 Subject: [PATCH] fix autocorrection for password type, add isSecure field commit_hash:22c0a70edb259644142904b5165d370db94b7d33 --- .../Extensions/DivInputExtensions.swift | 35 ++++++++- .../Extensions/DivInputExtentionsTests.swift | 75 ++++++++++++------- .../ios/DivKitTests/Utils/DivBuilders.swift | 2 + .../LayoutKit/Blocks/TextInputBlock.swift | 20 +++-- ...TextInputBlock+UIViewRenderableBlock.swift | 40 ++++------ 5 files changed, 108 insertions(+), 64 deletions(-) diff --git a/client/ios/DivKit/Extensions/DivInputExtensions.swift b/client/ios/DivKit/Extensions/DivInputExtensions.swift index 427a37855..eb2fde97d 100644 --- a/client/ios/DivKit/Extensions/DivInputExtensions.swift +++ b/client/ios/DivKit/Extensions/DivInputExtensions.swift @@ -89,7 +89,9 @@ extension DivInput: DivBlockModeling { paddings: paddings?.resolve(context), isEnabled: resolveIsEnabled(expressionResolver), maxLength: resolveMaxLength(expressionResolver), - shouldClearFocus: shouldClearFocus + shouldClearFocus: shouldClearFocus, + autocorrection: keyboardType.autocorrection, + isSecure: keyboardType.isSecure ) } @@ -208,7 +210,7 @@ extension DivAlignmentVertical { extension DivInput.KeyboardType { fileprivate var system: TextInputBlock.InputType { switch self { - case .singleLineText, .multiLineText: + case .singleLineText, .multiLineText, .password: return .default case .phone: return .keyboard(.phonePad) @@ -218,9 +220,34 @@ extension DivInput.KeyboardType { return .keyboard(.emailAddress) case .uri: return .keyboard(.URL) + } + } + + fileprivate var autocorrection: Bool { + switch self { + case .singleLineText, + .multiLineText: + true + case .phone, + .number, + .email, + .uri, + .password: + false + } + } + + fileprivate var isSecure: Bool { + switch self { case .password: - DivKitLogger.warning("Keyboard type '\(self.rawValue)' is not supported") - return .default + true + case .singleLineText, + .multiLineText, + .phone, + .number, + .email, + .uri: + false } } } diff --git a/client/ios/DivKitTests/Extensions/DivInputExtentionsTests.swift b/client/ios/DivKitTests/Extensions/DivInputExtentionsTests.swift index 477f25582..0ac14e3a6 100644 --- a/client/ios/DivKitTests/Extensions/DivInputExtentionsTests.swift +++ b/client/ios/DivKitTests/Extensions/DivInputExtentionsTests.swift @@ -18,19 +18,9 @@ final class DivInputExtensionsTests: XCTestCase { context: context ) - let expectedBlock = StateBlock( - child: DecoratingBlock( - child: TextInputBlock( - hint: NSAttributedString(string: ""), - textValue: context.makeBinding(variableName: "input_variable", defaultValue: ""), - textTypo: Typo(font: fontSpecifiers.text.font(weight: .regular, size: 12)) - .with(color: Color.colorWithARGBHexCode(0xFF_00_00_00)), - path: .root + "0", - layoutDirection: .leftToRight - ), - accessibilityElement: accessibility(label: "Hello!") - ), - ids: [] + let expectedBlock = makeExpectedBlockBlock( + accessibilityElement: accessibility(label: "Hello!"), + context: context ) assertEqual(block, expectedBlock) @@ -45,21 +35,56 @@ final class DivInputExtensionsTests: XCTestCase { context: context ) - let expectedBlock = StateBlock( - child: DecoratingBlock( - child: TextInputBlock( - hint: NSAttributedString(string: ""), - textValue: context.makeBinding(variableName: "input_variable", defaultValue: ""), - textTypo: Typo(font: fontSpecifiers.text.font(weight: .regular, size: 12)) - .with(color: Color.colorWithARGBHexCode(0xFF_00_00_00)), - path: .root + "0", - layoutDirection: .leftToRight - ), - accessibilityElement: accessibility(label: "Description") + let expectedBlock = makeExpectedBlockBlock( + accessibilityElement: accessibility(label: "Description"), + context: context + ) + + assertEqual(block, expectedBlock) + } + + func test_WithPasswordType() { + let block = makeBlock( + divInput( + keyboardType: .password, + textVariable: "input_variable" ), - ids: [] + context: context + ) + + let expectedBlock = makeExpectedBlockBlock( + autocorrection: false, + isSecure: true, + multilineMode: false, + context: context ) assertEqual(block, expectedBlock) } } + +private func makeExpectedBlockBlock( + accessibilityElement: AccessibilityElement? = nil, + autocorrection: Bool = true, + isSecure: Bool = false, + multilineMode: Bool = true, + context: DivBlockModelingContext +) -> StateBlock { + StateBlock( + child: DecoratingBlock( + child: TextInputBlock( + hint: NSAttributedString(string: ""), + textValue: context.makeBinding(variableName: "input_variable", defaultValue: ""), + textTypo: Typo(font: fontSpecifiers.text.font(weight: .regular, size: 12)) + .with(color: Color.colorWithARGBHexCode(0xFF_00_00_00)), + multiLineMode: multilineMode, + path: .root + "0" + "input", + layoutDirection: .leftToRight, + autocorrection: autocorrection, + isSecure: isSecure + ), + accessibilityElement: accessibilityElement ?? accessibility(label: "Hello!") + ), + ids: [] + ) +} diff --git a/client/ios/DivKitTests/Utils/DivBuilders.swift b/client/ios/DivKitTests/Utils/DivBuilders.swift index 95bf8a14a..875f9afd5 100644 --- a/client/ios/DivKitTests/Utils/DivBuilders.swift +++ b/client/ios/DivKitTests/Utils/DivBuilders.swift @@ -69,10 +69,12 @@ func divGifImage( func divInput( accessibility: DivAccessibility? = nil, + keyboardType: DivInput.KeyboardType? = nil, textVariable: String ) -> Div { .divInput(DivInput( accessibility: accessibility, + keyboardType: keyboardType.map { .value($0) }, textVariable: textVariable )) } diff --git a/client/ios/LayoutKit/LayoutKit/Blocks/TextInputBlock.swift b/client/ios/LayoutKit/LayoutKit/Blocks/TextInputBlock.swift index 8ad1150bb..5dfaf9917 100644 --- a/client/ios/LayoutKit/LayoutKit/Blocks/TextInputBlock.swift +++ b/client/ios/LayoutKit/LayoutKit/Blocks/TextInputBlock.swift @@ -8,17 +8,11 @@ public final class TextInputBlock: BlockWithTraits { public enum InputType: Equatable { public enum KeyboardType: Equatable { case `default` - case asciiCapable - case numbersAndPunctuation case URL - case numberPad case phonePad case namePhonePad case emailAddress case decimalPad - case twitter - case webSearch - case asciiCapableNumberPad } public struct SelectionItem: Equatable { @@ -95,6 +89,8 @@ public final class TextInputBlock: BlockWithTraits { public let paddings: EdgeInsets? public let isEnabled: Bool public let maxLength: Int? + public let autocorrection: Bool + public let isSecure: Bool let shouldClearFocus: Variable @@ -128,7 +124,9 @@ public final class TextInputBlock: BlockWithTraits { paddings: EdgeInsets? = nil, isEnabled: Bool = true, maxLength: Int? = nil, - shouldClearFocus: Variable = .constant(true) + shouldClearFocus: Variable = .constant(true), + autocorrection: Bool = false, + isSecure: Bool = false ) { self.widthTrait = widthTrait self.heightTrait = heightTrait @@ -160,6 +158,8 @@ public final class TextInputBlock: BlockWithTraits { self.isEnabled = isEnabled self.maxLength = maxLength self.shouldClearFocus = shouldClearFocus + self.autocorrection = autocorrection + self.isSecure = isSecure } public var intrinsicContentWidth: CGFloat { @@ -240,6 +240,8 @@ extension TextInputBlock { && lhs.textTypo == rhs.textTypo && lhs.textValue.value == rhs.textValue.value && lhs.widthTrait == rhs.widthTrait + && lhs.autocorrection == rhs.autocorrection + && lhs.isSecure == rhs.isSecure } } @@ -280,7 +282,9 @@ extension TextInputBlock: ElementFocusUpdating { textAlignmentVertical: textAlignmentVertical, paddings: paddings, isEnabled: isEnabled, - maxLength: maxLength + maxLength: maxLength, + autocorrection: autocorrection, + isSecure: isSecure ) } } diff --git a/client/ios/LayoutKit/LayoutKit/UI/Blocks/TextInputBlock+UIViewRenderableBlock.swift b/client/ios/LayoutKit/LayoutKit/UI/Blocks/TextInputBlock+UIViewRenderableBlock.swift index 904dc51ae..32d30618d 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Blocks/TextInputBlock+UIViewRenderableBlock.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Blocks/TextInputBlock+UIViewRenderableBlock.swift @@ -14,6 +14,8 @@ extension TextInputBlock { inputView.setLayoutDirection(layoutDirection) inputView.setInputType(inputType) inputView.setInputAccessoryView(accessoryView) + inputView.setAutocorrection(autocorrection) + inputView.setSecure(isSecure) inputView.setAutocapitalizationType(autocapitalizationType) inputView.setEnterKeyType(enterKeyType) inputView.setValidators(validators) @@ -195,9 +197,6 @@ private final class TextInputBlockView: BlockView, VisibleBoundsTrackingLeaf { private func setKeyboardType(_ type: TextInputBlock.InputType.KeyboardType) { multiLineInput.keyboardType = type.uiType singleLineInput.keyboardType = type.uiType - - singleLineInput.autocorrectionType = type.autoCorrectionType - multiLineInput.autocorrectionType = type.autoCorrectionType } func setInputAccessoryView(_ accessoryView: ViewType?) { @@ -205,6 +204,17 @@ private final class TextInputBlockView: BlockView, VisibleBoundsTrackingLeaf { singleLineInput.inputAccessoryView = accessoryView } + func setAutocorrection(_ isEnabled: Bool) { + let uiType: UITextAutocorrectionType = isEnabled ? .yes : .no + multiLineInput.autocorrectionType = uiType + singleLineInput.autocorrectionType = uiType + } + + func setSecure(_ isSecure: Bool) { + multiLineInput.isSecureTextEntry = isSecure + singleLineInput.isSecureTextEntry = isSecure + } + func setAutocapitalizationType(_ type: TextInputBlock.AutocapitalizationType) { singleLineInput.autocapitalizationType = type.uiType multiLineInput.autocapitalizationType = type.uiType @@ -777,14 +787,8 @@ extension TextInputBlock.InputType.KeyboardType { switch self { case .default: .default - case .asciiCapable: - .asciiCapable - case .numbersAndPunctuation: - .numbersAndPunctuation case .URL: .URL - case .numberPad: - .numberPad case .phonePad: .phonePad case .namePhonePad: @@ -793,24 +797,6 @@ extension TextInputBlock.InputType.KeyboardType { .emailAddress case .decimalPad: .decimalPad - case .twitter: - .twitter - case .webSearch: - .webSearch - case .asciiCapableNumberPad: - .asciiCapableNumberPad - } - } - - fileprivate var autoCorrectionType: UITextAutocorrectionType { - switch self { - case .URL, .webSearch, .twitter, .emailAddress: - return .no - case .default: - return .default - case .asciiCapable, .numbersAndPunctuation, .numberPad, .phonePad, - .namePhonePad, .decimalPad, .asciiCapableNumberPad: - return .yes } } }