VoiceOver wip

This commit is contained in:
Justin Mazzocchi 2021-02-02 14:33:54 -08:00
parent 82a1813064
commit 29d8d609b5
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
3 changed files with 59 additions and 1 deletions

View file

@ -11,6 +11,7 @@
"account.domain-block.confirm-%@" = "Block domain %@?"; "account.domain-block.confirm-%@" = "Block domain %@?";
"account.domain-unblock-%@" = "Unblock domain %@"; "account.domain-unblock-%@" = "Unblock domain %@";
"account.domain-unblock.confirm-%@" = "Unblock domain %@?"; "account.domain-unblock.confirm-%@" = "Unblock domain %@?";
"account.field.activate-link-accessibility-action-%@" = "Activate link: %@";
"account.field.verified" = "Verified %@"; "account.field.verified" = "Verified %@";
"account.follow" = "Follow"; "account.follow" = "Follow";
"account.following" = "Following"; "account.following" = "Following";

View file

@ -1,16 +1,22 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Combine
import Mastodon import Mastodon
import UIKit import UIKit
final class AccountFieldView: UIView { final class AccountFieldView: UIView {
let nameLabel = UILabel() let nameLabel = UILabel()
let valueTextView = TouchFallthroughTextView() let valueTextView = TouchFallthroughTextView()
private var cancellables = Set<AnyCancellable>()
// swiftlint:disable:next function_body_length // swiftlint:disable:next function_body_length
init(name: String, value: NSAttributedString, verifiedAt: Date?, emojis: [Emoji]) { init(name: String, value: NSAttributedString, verifiedAt: Date?, emojis: [Emoji]) {
super.init(frame: .zero) super.init(frame: .zero)
NotificationCenter.default.publisher(for: UIAccessibility.voiceOverStatusDidChangeNotification)
.sink { [weak self] _ in self?.configureUserInteractionEnabledForAccessibility() }
.store(in: &cancellables)
backgroundColor = .systemBackground backgroundColor = .systemBackground
let nameBackgroundView = UIView() let nameBackgroundView = UIView()
@ -134,6 +140,51 @@ final class AccountFieldView: UIView {
valueBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor), valueBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor),
valueBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) valueBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor)
]) ])
// isAccessibilityElement = true
let accessibilityAttributedLabel = NSMutableAttributedString(attributedString: mutableName)
accessibilityAttributedLabel.appendWithSeparator(mutableValue)
if let verifiedAt = verifiedAt {
accessibilityAttributedLabel.appendWithSeparator(
String.localizedStringWithFormat(
NSLocalizedString("account.field.verified", comment: ""),
Self.dateFormatter.string(from: verifiedAt)))
}
isAccessibilityElement = true
var accessibilityCustomActions = [UIAccessibilityCustomAction]()
mutableValue.enumerateAttribute(
.link,
in: NSRange(location: 0, length: mutableValue.length),
options: []) { attribute, range, _ in
guard let url = attribute as? URL else { return }
accessibilityCustomActions.append(
UIAccessibilityCustomAction(
name: String.localizedStringWithFormat(
NSLocalizedString("account.field.activate-link-accessibility-action-%@", comment: ""),
mutableValue.attributedSubstring(from: range).string)) { [weak self] _ in
guard let valueTextView = self?.valueTextView else { return false }
_ = valueTextView.delegate?.textView?(
valueTextView,
shouldInteractWith: url,
in: range,
interaction: .invokeDefaultAction)
return true
})
}
self.accessibilityAttributedLabel = accessibilityAttributedLabel
self.accessibilityCustomActions = accessibilityCustomActions
configureUserInteractionEnabledForAccessibility()
} }
@available(*, unavailable) @available(*, unavailable)
@ -150,4 +201,8 @@ private extension AccountFieldView {
return formatter return formatter
}() }()
func configureUserInteractionEnabledForAccessibility() {
valueTextView.isUserInteractionEnabled = !UIAccessibility.isVoiceOverRunning
}
} }

View file

@ -26,7 +26,9 @@ final class TouchFallthroughTextView: UITextView {
} }
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
shouldFallthrough ? urlAndRect(at: point) != nil : super.point(inside: point, with: event) guard !UIAccessibility.isVoiceOverRunning else { return super.point(inside: point, with: event) }
return shouldFallthrough ? urlAndRect(at: point) != nil : super.point(inside: point, with: event)
} }
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {