Various Voice Over Improvements

This commit is contained in:
Ilya Laktyushin 2021-03-02 03:20:46 +04:00
parent 3ea2032fa7
commit 5f0a33e414
6 changed files with 4410 additions and 4378 deletions

View File

@ -4683,6 +4683,16 @@ Sorry for the inconvenience.";
"VoiceOver.MessageContextReply" = "Reply";
"VoiceOver.MessageContextOpenMessageMenu" = "Open message menu";
"VoiceOver.Keyboard" = "Keyboard";
"VoiceOver.Stickers" = "Stickers";
"VoiceOver.ScheduledMessages" = "Scheduled Messages";
"VoiceOver.BotCommands" = "Bot Commands";
"VoiceOver.BotKeyboard" = "Bot Keyboard";
"VoiceOver.SilentPostOn" = "Silent Broadcast On";
"VoiceOver.SilentPostOff" = "Silent Broadcast Off";
"VoiceOver.SelfDestructTimerOn" = "Self-destruct Timer: %@";
"VoiceOver.SelfDestructTimerOff" = "Self-destruct Timer Off";
"ProxyServer.VoiceOver.Active" = "Active";
"Conversation.ScheduleMessage.Title" = "Schedule Message";

View File

@ -142,6 +142,8 @@ private final class ItemNode: ASDisplayNode {
super.init()
self.isAccessibilityElement = true
self.extractedContainerNode.contentNode.addSubnode(self.extractedBackgroundNode)
self.extractedContainerNode.contentNode.addSubnode(self.titleContainer)
self.titleContainer.addSubnode(self.titleNode)
@ -495,6 +497,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
super.init()
self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.showsVerticalScrollIndicator = false
self.scrollNode.view.scrollsToTop = false
self.scrollNode.view.delaysContentTouches = false
self.scrollNode.view.canCancelContentTouches = true

View File

@ -124,6 +124,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
private let dimNode: ASDisplayNode
private let withoutBlurDimNode: ASDisplayNode
private let dismissNode: ASDisplayNode
private let dismissAccessibilityArea: AccessibilityAreaNode
private let clippingNode: ASDisplayNode
private let scrollNode: ASScrollNode
@ -184,9 +185,9 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
self.withoutBlurDimNode.alpha = 0.0
self.dismissNode = ASDisplayNode()
self.dismissNode.isAccessibilityElement = true
self.dismissNode.accessibilityLabel = presentationData.strings.VoiceOver_DismissContextMenu
self.dismissNode.accessibilityTraits = .button
self.dismissAccessibilityArea = AccessibilityAreaNode()
self.dismissAccessibilityArea.accessibilityLabel = presentationData.strings.VoiceOver_DismissContextMenu
self.dismissAccessibilityArea.accessibilityTraits = .button
self.clippingNode = ASDisplayNode()
self.clippingNode.clipsToBounds = true
@ -242,6 +243,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
self.clippingNode.addSubnode(self.scrollNode)
self.scrollNode.addSubnode(self.dismissNode)
self.scrollNode.addSubnode(self.dismissAccessibilityArea)
self.scrollNode.addSubnode(self.actionsContainerNode)
self.reactionContextNode.flatMap(self.addSubnode)
@ -439,6 +441,11 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
self.initializeContent()
self.dismissAccessibilityArea.activate = { [weak self] in
self?.dimNodeTapped()
return true
}
}
deinit {
@ -1406,7 +1413,8 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
}
transition.updateFrame(node: self.dismissNode, frame: CGRect(origin: CGPoint(), size: scrollNode.view.contentSize))
transition.updateFrame(node: self.dismissNode, frame: CGRect(origin: CGPoint(), size: self.scrollNode.view.contentSize))
self.dismissAccessibilityArea.frame = CGRect(origin: CGPoint(), size: self.scrollNode.view.contentSize)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {

View File

@ -19,37 +19,37 @@ import Speak
private let accessoryButtonFont = Font.medium(14.0)
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
private final class AccessoryItemIconButton: HighlightTrackingButton {
private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
private let item: ChatTextInputAccessoryItem
private var width: CGFloat
private let imageNode: ASImageNode
private var imageEdgeInsets = UIEdgeInsets()
init(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) {
self.imageNode = ASImageNode()
self.imageNode.isLayerBacked = true
self.imageNode.displaysAsynchronously = false
self.imageNode.displayWithoutProcessing = true
self.item = item
let (image, text, alpha, insets) = AccessoryItemIconButton.imageAndInsets(item: item, theme: theme, strings: strings)
let (image, text, accessibilityLabel, alpha, insets) = AccessoryItemIconButtonNode.imageAndInsets(item: item, theme: theme, strings: strings)
self.width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: text, strings: strings)
self.width = AccessoryItemIconButtonNode.calculateWidth(item: item, image: image, text: text, strings: strings)
super.init(frame: CGRect())
super.init()
self.isAccessibilityElement = true
self.accessibilityTraits = [.button]
self.addSubnode(self.imageNode)
if let text = text {
self.titleLabel?.font = accessoryButtonFont
self.setTitleColor(theme.chat.inputPanel.inputControlColor, for: [])
self.setTitle(text, for: [])
self.setAttributedTitle(NSAttributedString(string: text, font: accessoryButtonFont, textColor: theme.chat.inputPanel.inputControlColor), for: .normal)
} else {
self.setAttributedTitle(NSAttributedString(), for: .normal)
}
self.imageNode.image = image
self.imageNode.alpha = alpha
self.imageEdgeInsets = insets
self.accessibilityLabel = accessibilityLabel
self.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
@ -64,51 +64,51 @@ private final class AccessoryItemIconButton: HighlightTrackingButton {
}
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
let (image, text, alpha, insets) = AccessoryItemIconButton.imageAndInsets(item: item, theme: theme, strings: strings)
let (image, text, accessibilityLabel, alpha, insets) = AccessoryItemIconButtonNode.imageAndInsets(item: item, theme: theme, strings: strings)
self.width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: text, strings: strings)
self.width = AccessoryItemIconButtonNode.calculateWidth(item: item, image: image, text: text, strings: strings)
if let text = text {
self.titleLabel?.font = accessoryButtonFont
self.setTitleColor(theme.chat.inputPanel.inputControlColor, for: [])
self.setTitle(text, for: [])
self.setAttributedTitle(NSAttributedString(string: text, font: accessoryButtonFont, textColor: theme.chat.inputPanel.inputControlColor), for: .normal)
} else {
self.setTitle("", for: [])
self.setAttributedTitle(NSAttributedString(), for: .normal)
}
self.imageNode.image = image
self.imageEdgeInsets = insets
self.imageNode.alpha = alpha
self.accessibilityLabel = accessibilityLabel
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, CGFloat, UIEdgeInsets) {
static func imageAndInsets(item: ChatTextInputAccessoryItem, theme: PresentationTheme, strings: PresentationStrings) -> (UIImage?, String?, String, CGFloat, UIEdgeInsets) {
switch item {
case .keyboard:
return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldKeyboardImage(theme), nil, strings.VoiceOver_Keyboard, 1.0, UIEdgeInsets())
case let .stickers(enabled):
return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, enabled ? 1.0 : 0.4, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldStickersImage(theme), nil, strings.VoiceOver_Stickers, enabled ? 1.0 : 0.4, UIEdgeInsets())
case .inputButtons:
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldInputButtonsImage(theme), nil, strings.VoiceOver_BotKeyboard, 1.0, UIEdgeInsets())
case .commands:
return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldCommandsImage(theme), nil, strings.VoiceOver_BotCommands, 1.0, UIEdgeInsets())
case let .silentPost(value):
if value {
return (PresentationResourcesChat.chatInputTextFieldSilentPostOnImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldSilentPostOnImage(theme), nil, strings.VoiceOver_SilentPostOn, 1.0, UIEdgeInsets())
} else {
return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets())
}
case let .messageAutoremoveTimeout(timeout):
if let timeout = timeout {
return (nil, shortTimeIntervalString(strings: strings, value: timeout), 1.0, UIEdgeInsets())
return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).0, 1.0, UIEdgeInsets())
} else {
return (PresentationResourcesChat.chatInputTextFieldTimerImage(theme), nil, 1.0, UIEdgeInsets(top: 0.0, left: 0.0, bottom: 1.0, right: 0.0))
return (PresentationResourcesChat.chatInputTextFieldTimerImage(theme), nil, strings.VoiceOver_SelfDestructTimerOff, 1.0, UIEdgeInsets(top: 0.0, left: 0.0, bottom: 1.0, right: 0.0))
}
case .scheduledMessages:
return (PresentationResourcesChat.chatInputTextFieldScheduleImage(theme), nil, 1.0, UIEdgeInsets())
return (PresentationResourcesChat.chatInputTextFieldScheduleImage(theme), nil, strings.VoiceOver_ScheduledMessages, 1.0, UIEdgeInsets())
}
}
@ -220,7 +220,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var audioRecordingCancelIndicator: ChatTextInputAudioRecordingCancelIndicator?
var animatingBinNode: AnimationNode?
private var accessoryItemButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButton)] = []
private var accessoryItemButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)] = []
private var validLayout: (CGFloat, CGFloat, CGFloat, UIEdgeInsets, CGFloat, LayoutMetrics, Bool)?
@ -316,9 +316,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
if updateAccessoryButtons {
var updatedButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButton)] = []
var updatedButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)] = []
for item in accessoryItems {
var itemAndButton: (ChatTextInputAccessoryItem, AccessoryItemIconButton)?
var itemAndButton: (ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)?
for i in 0 ..< self.accessoryItemButtons.count {
if self.accessoryItemButtons[i].0 == item {
itemAndButton = self.accessoryItemButtons[i]
@ -327,14 +327,14 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
}
if itemAndButton == nil {
let button = AccessoryItemIconButton(item: item, theme: currentState.theme, strings: currentState.strings)
button.addTarget(self, action: #selector(self.accessoryItemButtonPressed(_:)), for: [.touchUpInside])
let button = AccessoryItemIconButtonNode(item: item, theme: currentState.theme, strings: currentState.strings)
button.addTarget(self, action: #selector(self.accessoryItemButtonPressed(_:)), forControlEvents: .touchUpInside)
itemAndButton = (item, button)
}
updatedButtons.append(itemAndButton!)
}
for (_, button) in self.accessoryItemButtons {
button.removeFromSuperview()
button.removeFromSupernode()
}
self.accessoryItemButtons = updatedButtons
}
@ -904,11 +904,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
updateAccessoryButtons = true
}
var removeAccessoryButtons: [AccessoryItemIconButton]?
var removeAccessoryButtons: [AccessoryItemIconButtonNode]?
if updateAccessoryButtons {
var updatedButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButton)] = []
var updatedButtons: [(ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)] = []
for item in interfaceState.inputTextPanelState.accessoryItems {
var itemAndButton: (ChatTextInputAccessoryItem, AccessoryItemIconButton)?
var itemAndButton: (ChatTextInputAccessoryItem, AccessoryItemIconButtonNode)?
for i in 0 ..< self.accessoryItemButtons.count {
if self.accessoryItemButtons[i].0 == item {
itemAndButton = self.accessoryItemButtons[i]
@ -917,8 +917,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
}
if itemAndButton == nil {
let button = AccessoryItemIconButton(item: item, theme: interfaceState.theme, strings: interfaceState.strings)
button.addTarget(self, action: #selector(self.accessoryItemButtonPressed(_:)), for: [.touchUpInside])
let button = AccessoryItemIconButtonNode(item: item, theme: interfaceState.theme, strings: interfaceState.strings)
button.addTarget(self, action: #selector(self.accessoryItemButtonPressed(_:)), forControlEvents: .touchUpInside)
itemAndButton = (item, button)
}
updatedButtons.append(itemAndButton!)
@ -930,7 +930,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
removeAccessoryButtons!.append(button)
} else {
button.removeFromSuperview()
button.removeFromSupernode()
}
}
self.accessoryItemButtons = updatedButtons
@ -1343,8 +1343,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let buttonSize = CGSize(width: button.buttonWidth, height: minimalInputHeight)
button.updateLayout(size: buttonSize)
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonTopRight.x - buttonSize.width, y: nextButtonTopRight.y + floor((minimalInputHeight - buttonSize.height) / 2.0)), size: buttonSize)
if button.superview == nil {
self.view.addSubview(button)
if button.supernode == nil {
self.addSubnode(button)
button.frame = buttonFrame.offsetBy(dx: -additionalOffset, dy: 0.0)
transition.updateFrame(layer: button.layer, frame: buttonFrame)
if animatedTransition {
@ -1364,7 +1364,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
transition.updateFrame(layer: button.layer, frame: buttonFrame)
button.layer.animateScale(from: 1.0, to: 0.2, duration: 0.25, removeOnCompletion: false)
button.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak button] _ in
button?.removeFromSuperview()
button?.removeFromSupernode()
})
}
}