mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-27 07:48:42 +00:00
Accessibility updates
This commit is contained in:
parent
d8cd427f55
commit
be6bbbc6ae
@ -1,6 +1,6 @@
|
||||
|
||||
public enum ContextMenuActionContent {
|
||||
case text(String)
|
||||
case text(title: String, accessibilityLabel: String)
|
||||
case icon(UIImage)
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,8 @@ final class ContextMenuActionNode: ASDisplayNode {
|
||||
self.actionArea.accessibilityTraits = UIAccessibilityTraitButton
|
||||
|
||||
switch action.content {
|
||||
case let .text(title):
|
||||
self.actionArea.accessibilityLabel = title
|
||||
case let .text(title, accessibilityLabel):
|
||||
self.actionArea.accessibilityLabel = accessibilityLabel
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.isUserInteractionEnabled = false
|
||||
|
@ -275,6 +275,49 @@ public final class TextNodeLayout: NSObject {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func allAttributeRects(name: String) -> [(Any, CGRect)] {
|
||||
guard let attributedString = self.attributedString else {
|
||||
return []
|
||||
}
|
||||
var result: [(Any, CGRect)] = []
|
||||
attributedString.enumerateAttribute(NSAttributedStringKey(rawValue: name), in: NSRange(location: 0, length: attributedString.length), options: []) { (value, range, _) in
|
||||
if let value = value, range.length != 0 {
|
||||
var coveringRect = CGRect()
|
||||
for line in self.lines {
|
||||
let lineRange = NSIntersectionRange(range, line.range)
|
||||
if lineRange.length != 0 {
|
||||
var leftOffset: CGFloat = 0.0
|
||||
if lineRange.location != line.range.location {
|
||||
leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil))
|
||||
}
|
||||
var rightOffset: CGFloat = line.frame.width
|
||||
if lineRange.location + lineRange.length != line.range.length {
|
||||
var secondaryOffset: CGFloat = 0.0
|
||||
let rawOffset = CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, &secondaryOffset)
|
||||
rightOffset = ceil(rawOffset)
|
||||
if !rawOffset.isEqual(to: secondaryOffset) {
|
||||
rightOffset = ceil(secondaryOffset)
|
||||
}
|
||||
}
|
||||
var lineFrame = CGRect(origin: CGPoint(x: line.frame.origin.x, y: line.frame.origin.y - line.frame.size.height + self.firstLineOffset), size: line.frame.size)
|
||||
lineFrame = displayLineFrame(frame: lineFrame, isRTL: line.isRTL, boundingRect: CGRect(origin: CGPoint(), size: self.size), cutout: self.cutout)
|
||||
|
||||
let rect = CGRect(origin: CGPoint(x: lineFrame.minX + leftOffset + self.insets.left, y: lineFrame.minY + self.insets.top), size: CGSize(width: rightOffset - leftOffset, height: lineFrame.size.height))
|
||||
if coveringRect.isEmpty {
|
||||
coveringRect = rect
|
||||
} else {
|
||||
coveringRect = coveringRect.union(rect)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !coveringRect.isEmpty {
|
||||
result.append((value, coveringRect))
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func lineAndAttributeRects(name: String, at index: Int) -> [(CGRect, CGRect)]? {
|
||||
if let attributedString = self.attributedString {
|
||||
var range = NSRange()
|
||||
@ -313,6 +356,110 @@ public final class TextNodeLayout: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
private final class TextAccessibilityOverlayElement: UIAccessibilityElement {
|
||||
private let url: String
|
||||
private let openUrl: (String) -> Void
|
||||
|
||||
init(accessibilityContainer: Any, url: String, openUrl: @escaping (String) -> Void) {
|
||||
self.url = url
|
||||
self.openUrl = openUrl
|
||||
|
||||
super.init(accessibilityContainer: accessibilityContainer)
|
||||
}
|
||||
|
||||
override func accessibilityActivate() -> Bool {
|
||||
self.openUrl(self.url)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private final class TextAccessibilityOverlayNodeView: UIView {
|
||||
fileprivate var cachedLayout: TextNodeLayout? {
|
||||
didSet {
|
||||
self.currentAccessibilityNodes?.forEach({ $0.removeFromSupernode() })
|
||||
self.currentAccessibilityNodes = nil
|
||||
}
|
||||
}
|
||||
fileprivate let openUrl: (String) -> Void
|
||||
|
||||
private var currentAccessibilityNodes: [AccessibilityAreaNode]?
|
||||
|
||||
override var accessibilityElements: [Any]? {
|
||||
get {
|
||||
if let _ = self.currentAccessibilityNodes {
|
||||
return nil
|
||||
}
|
||||
guard let cachedLayout = self.cachedLayout else {
|
||||
return nil
|
||||
}
|
||||
let urlAttributesAndRects = cachedLayout.allAttributeRects(name: "UrlAttributeT")
|
||||
|
||||
var urlElements: [AccessibilityAreaNode] = []
|
||||
for (value, rect) in urlAttributesAndRects {
|
||||
let element = AccessibilityAreaNode()
|
||||
element.accessibilityLabel = value as? String ?? ""
|
||||
element.frame = rect
|
||||
element.accessibilityTraits = UIAccessibilityTraitLink
|
||||
element.activate = { [weak self] in
|
||||
self?.openUrl(value as? String ?? "")
|
||||
return true
|
||||
}
|
||||
self.addSubnode(element)
|
||||
urlElements.append(element)
|
||||
}
|
||||
self.currentAccessibilityNodes = urlElements
|
||||
return nil
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
||||
init(openUrl: @escaping (String) -> Void) {
|
||||
self.openUrl = openUrl
|
||||
|
||||
super.init(frame: CGRect())
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
public final class TextAccessibilityOverlayNode: ASDisplayNode {
|
||||
public var cachedLayout: TextNodeLayout? {
|
||||
didSet {
|
||||
if self.isNodeLoaded {
|
||||
(self.view as? TextAccessibilityOverlayNodeView)?.cachedLayout = self.cachedLayout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var openUrl: ((String) -> Void)?
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
|
||||
let openUrl: (String) -> Void = { [weak self] url in
|
||||
self?.openUrl?(url)
|
||||
}
|
||||
|
||||
self.isAccessibilityElement = false
|
||||
|
||||
self.setViewBlock({
|
||||
return TextAccessibilityOverlayNodeView(openUrl: openUrl)
|
||||
})
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
(self.view as? TextAccessibilityOverlayNodeView)?.cachedLayout = self.cachedLayout
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public class TextNode: ASDisplayNode {
|
||||
public private(set) var cachedLayout: TextNodeLayout?
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user