Skip to content

Commit

Permalink
Fix issue where text entry do not have "text field" or a hint in the …
Browse files Browse the repository at this point in the history
…description (#186)

Fixes the issue where text fields and text views do not have "text field" or a hint in their description

---------

Co-authored-by: David Brunow <[email protected]>
Co-authored-by: Nick Entin <[email protected]>
  • Loading branch information
3 people authored Feb 23, 2024
1 parent 07c283f commit f039d27
Show file tree
Hide file tree
Showing 22 changed files with 381 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Example/AccessibilitySnapshot.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
1104A8CF2B580AC500B6715F /* SwiftUITextEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1104A8CE2B580AC500B6715F /* SwiftUITextEntry.swift */; };
1104A8D12B595FF600B6715F /* TextFieldViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1104A8D02B595FF600B6715F /* TextFieldViewController.swift */; };
112909BC2B63E57B00B4EBEB /* TextViewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112909BB2B63E57B00B4EBEB /* TextViewViewController.swift */; };
1635CE4E251EAC6700907101 /* SnapshotTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1635CE4D251EAC6700907101 /* SnapshotTestingTests.swift */; };
3D04B6D6211558B0006218A4 /* AccessibilityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D04B6D5211558B0006218A4 /* AccessibilityViewController.swift */; };
3D04B6D921155942006218A4 /* LabelAccessibilityPropertiesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D04B6D821155942006218A4 /* LabelAccessibilityPropertiesViewController.swift */; };
Expand Down Expand Up @@ -78,6 +81,9 @@

/* Begin PBXFileReference section */
0BFCB4FD6BC17AB232B26E72 /* Pods_UnitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_UnitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1104A8CE2B580AC500B6715F /* SwiftUITextEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUITextEntry.swift; sourceTree = "<group>"; };
1104A8D02B595FF600B6715F /* TextFieldViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldViewController.swift; sourceTree = "<group>"; };
112909BB2B63E57B00B4EBEB /* TextViewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewViewController.swift; sourceTree = "<group>"; };
1635CE4D251EAC6700907101 /* SnapshotTestingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTestingTests.swift; sourceTree = "<group>"; };
358D84DCD315110A89BD052E /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = "<group>"; };
3A3192D7B9B16BD10FB517A2 /* Pods_SnapshotTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SnapshotTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -183,6 +189,7 @@
children = (
83A295832AC22D9D00DFBE4F /* UserInputLabelsViewController.swift */,
3D4674672116A3F100278B57 /* ViewAccessibilityPropertiesViewController.swift */,
1104A8CE2B580AC500B6715F /* SwiftUITextEntry.swift */,
3F8E5DB82535B25000276B32 /* SwiftUIView.swift */,
3FEF854E253846420072611F /* SwiftUIViewWithScrollView.swift */,
3D39BFAB223314C1009C3EF4 /* TabBarViewController.swift */,
Expand All @@ -202,6 +209,8 @@
3DBAC2902242F9B200EF4D0A /* LandmarkContainerViewController.swift */,
3D3F2E132263E6B900F7608E /* InvertColorsViewController.swift */,
3DDE7FF524C6D6BF00999ABA /* AccessibilityCustomActionsViewController.swift */,
1104A8D02B595FF600B6715F /* TextFieldViewController.swift */,
112909BB2B63E57B00B4EBEB /* TextViewViewController.swift */,
);
name = "Accessibility Screens";
sourceTree = "<group>";
Expand Down Expand Up @@ -626,14 +635,17 @@
3D04B6D921155942006218A4 /* LabelAccessibilityPropertiesViewController.swift in Sources */,
3DA12A3222405B9E00EB3C33 /* DataTableViewController.swift in Sources */,
3DEBF24E221018610065424F /* DefaultControlsViewController.swift in Sources */,
1104A8D12B595FF600B6715F /* TextFieldViewController.swift in Sources */,
3FEF854F253846420072611F /* SwiftUIViewWithScrollView.swift in Sources */,
3DF464FE220D594E0048D446 /* ElementSelectionViewController.swift in Sources */,
3DC488372212A7D4006D1E15 /* ModalAccessibilityViewController.swift in Sources */,
3DF46502220D7F9B0048D446 /* ElementOrderViewController.swift in Sources */,
112909BC2B63E57B00B4EBEB /* TextViewViewController.swift in Sources */,
3DDE7FF624C6D6BF00999ABA /* AccessibilityCustomActionsViewController.swift in Sources */,
3DBAC28F2242E7C700EF4D0A /* ListContainerViewController.swift in Sources */,
3DBEAA5B2222953E00FAE61D /* SwitchControlViewController.swift in Sources */,
3DBAC2912242F9B200EF4D0A /* LandmarkContainerViewController.swift in Sources */,
1104A8CF2B580AC500B6715F /* SwiftUITextEntry.swift in Sources */,
3D39BFAC223314C1009C3EF4 /* TabBarViewController.swift in Sources */,
3D04B6DB21155D92006218A4 /* ButtonAccessibilityTraitsViewController.swift in Sources */,
);
Expand Down
4 changes: 4 additions & 0 deletions Example/AccessibilitySnapshot/RootViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// limitations under the License.
//

import SwiftUI
import UIKit

final class RootViewController: UITableViewController {
Expand Down Expand Up @@ -61,6 +62,9 @@ final class RootViewController: UITableViewController {
("Landmark Container", { _ in return LandmarkContainerViewController() }),
("Invert Colors", { _ in return InvertColorsViewController() }),
("User Input Labels", { _ in return UserInputLabelsViewController() }),
("Text Field", { _ in return TextFieldViewController() }),
("Text View", { _ in return TextViewViewController() }),
("SwiftUI Text Entry", { _ in return UIHostingController(rootView: SwiftUITextEntry()) }),
]

super.init(nibName: nil, bundle: nil)
Expand Down
36 changes: 36 additions & 0 deletions Example/AccessibilitySnapshot/SwiftUITextEntry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// Copyright 2024 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import SwiftUI

struct SwiftUITextEntry: View {
var body: some View {
VStack {
TextField("SwiftUI Text Field", text: .constant(""))
TextField("SwiftUI Text Field", text: .constant("Value in Text Field"))
if #available(iOS 14.0, *) {
TextEditor(text: .constant(""))
}
}
}
}

struct SwiftUITextEntry_Previews: PreviewProvider {
static var previews: some View {
SwiftUITextEntry()
.previewLayout(.sizeThatFits)
}
}
94 changes: 94 additions & 0 deletions Example/AccessibilitySnapshot/TextFieldViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// Copyright 2024 Block Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Paralayout
import UIKit

final class TextFieldViewController: AccessibilityViewController {

// MARK: - UIViewController

override func loadView() {
self.view = View()
}
}

// MARK: -

private extension TextFieldViewController {

final class View: UIView {

// MARK: - Life Cycle

override init(frame: CGRect) {
super.init(frame: frame)

textFieldWithPlaceholder.placeholder = "Some placeholder text"

textFieldWithText.text = "Hello from Text Field"

textInputViews.forEach {
$0.layer.borderWidth = 1.0
$0.layer.borderColor = UIColor.lightGray.cgColor
addSubview($0)
}
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Private Properties

private let textFieldEmpty: UITextField = .init()

private let textFieldFirstResponder: UITextField = .init()

private let textFieldWithPlaceholder: UITextField = .init()

private let textFieldWithText: UITextField = .init()

private var textInputViews: [UIView] {
return [
textFieldEmpty,
textFieldFirstResponder,
textFieldWithPlaceholder,
textFieldWithText,
]
}

// MARK: - UIView

override func layoutSubviews() {
textInputViews.forEach { $0.frame.size = CGSize(width: 250, height: 30) }

let statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0

var distributionSpecifiers: [ViewDistributionSpecifying] = [ statusBarHeight.fixed, 1.flexible ]
for subview in textInputViews {
distributionSpecifiers.append(subview)
distributionSpecifiers.append(1.flexible)
}
applyVerticalSubviewDistribution(distributionSpecifiers)

textFieldFirstResponder.becomeFirstResponder()
}

}

}
89 changes: 89 additions & 0 deletions Example/AccessibilitySnapshot/TextViewViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// Copyright 2024 Block Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Paralayout
import UIKit

final class TextViewViewController: AccessibilityViewController {

// MARK: - UIViewController

override func loadView() {
self.view = View()
}
}

// MARK: -

private extension TextViewViewController {

final class View: UIView {

// MARK: - Life Cycle

override init(frame: CGRect) {
super.init(frame: frame)

textViewWithText.text = "Hello from Text View"

textInputViews.forEach {
$0.layer.borderWidth = 1.0
$0.layer.borderColor = UIColor.lightGray.cgColor
addSubview($0)
}
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Private Properties

private let textViewEmpty: UITextView = .init()

private let textViewFirstResponder: UITextView = .init()

private let textViewWithText: UITextView = .init()

private var textInputViews: [UIView] {
return [
textViewEmpty,
textViewFirstResponder,
textViewWithText,
]
}

// MARK: - UIView

override func layoutSubviews() {
textInputViews.forEach { $0.frame.size = CGSize(width: 250, height: 30) }

let statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0

var distributionSpecifiers: [ViewDistributionSpecifying] = [ statusBarHeight.fixed, 1.flexible ]
for subview in textInputViews {
distributionSpecifiers.append(subview)
distributionSpecifiers.append(1.flexible)
}
applyVerticalSubviewDistribution(distributionSpecifiers)

textViewFirstResponder.becomeFirstResponder()
}

}

}
33 changes: 33 additions & 0 deletions Example/SnapshotTests/SnapshotTestingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,39 @@ final class SnapshotTestingTests: XCTestCase {
assertSnapshot(matching: viewController, as: .imageWithHitTargets(), named: nameForDevice())
}

func testUIKitTextField() {
let viewController = TextFieldViewController()
viewController.view.frame = UIScreen.main.bounds

assertSnapshot(
matching: viewController,
as: .accessibilityImage,
named: nameForDevice()
)
}

func testUIKitTextView() {
let viewController = TextViewViewController()
viewController.view.frame = UIScreen.main.bounds

assertSnapshot(
matching: viewController,
as: .accessibilityImage,
named: nameForDevice()
)
}

func testSwiftUITextEntry() {
let view = SwiftUITextEntry()
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

assertSnapshot(
matching: view,
as: .accessibilityImage,
named: nameForDevice()
)
}

// MARK: - Private Methods

private func nameForDevice(baseName: String? = nil) -> String {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@

/* Description for an accessibility element indicating that it has custom actions available */
"custom_actions.description" = "Aktionen verfügbar";

/* Description for the 'text entry' accessibility trait */
"trait.text_field.description" = "Textfeld.";

/* Hint describing how to use elements with the 'text entry' accessibility trait */
"trait.text_field.hint" = "Zum Bearbeiten doppeltippen.";

/* Hint describing how to use elements with the 'text entry' accessibility trait when they are being edited */
"trait.text_field_is_editing.hint" = "Den Rotor für den Zuriff auf „Rechtschreibfehler verwenden";

/* Hint describing how to use elements with the 'text entry' and 'scrollable' accessibility traits */
"trait.scrollable_text_field.hint" = "Zum Bearbeiten doppeltippen., Den Rotor für den Zuriff auf „Rechtschreibfehler verwenden";

/* Description for the 'is editing' accessibility trait */
"trait.text_field_is_editing.description" = "Bearbeiten";
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@

/* Description for an accessibility element indicating that it has custom actions available */
"custom_actions.description" = "Actions Available";

/* Description for the 'text entry' accessibility trait */
"trait.text_field.description" = "Text Field.";

/* Hint describing how to use elements with the 'text entry' accessibility trait */
"trait.text_field.hint" = "Double tap to edit.";

/* Hint describing how to use elements with the 'text entry' accessibility trait when they are being edited */
"trait.text_field_is_editing.hint" = "Use the rotor to access Misspelled Words";

/* Hint describing how to use elements with the 'text entry' and 'scrollable' accessibility traits */
"trait.scrollable_text_field.hint" = "Double tap to edit., Use the rotor to access Misspelled Words";

/* Description for the 'is editing' accessibility trait */
"trait.text_field_is_editing.description" = "Is editing.";
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@

/* Description for an accessibility element indicating that it has custom actions available */
"custom_actions.description" = "Доступны действия";

/* Description for the 'text entry' accessibility trait */
"trait.text_field.description" = "текстовое поле.";

/* Hint describing how to use elements with the 'text entry' accessibility trait */
"trait.text_field.hint" = "коснитесь дважды, чтобы редактировать";

/* Hint describing how to use elements with the 'text entry' accessibility trait when they are being edited */
"trait.text_field_is_editing.hint" = "Используйте ротор для доступа к oбъeкту: Cлова с ошибками";

/* Hint describing how to use elements with the 'text entry' and 'scrollable' accessibility traits */
"trait.scrollable_text_field.hint" = "коснитесь дважды, чтобы редактировать., Используйте ротор для доступа к oбъeкту: Cлова с ошибками";

/* Description for the 'is editing' accessibility trait */
"trait.text_field_is_editing.description" = "Идет правка";
Loading

0 comments on commit f039d27

Please sign in to comment.