mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Various Voice Over improvements
This commit is contained in:
parent
657efeaff1
commit
3ea2032fa7
@ -4637,6 +4637,12 @@ Sorry for the inconvenience.";
|
|||||||
"VoiceOver.Chat.FileFrom" = "File, from: %@";
|
"VoiceOver.Chat.FileFrom" = "File, from: %@";
|
||||||
"VoiceOver.Chat.File" = "File";
|
"VoiceOver.Chat.File" = "File";
|
||||||
"VoiceOver.Chat.YourFile" = "Your file";
|
"VoiceOver.Chat.YourFile" = "Your file";
|
||||||
|
"VoiceOver.Chat.StickerFrom" = "Sticker, from: %@";
|
||||||
|
"VoiceOver.Chat.Sticker" = "Sticker";
|
||||||
|
"VoiceOver.Chat.YourSticker" = "Your sticker";
|
||||||
|
"VoiceOver.Chat.AnimatedStickerFrom" = "Animated sticker, from: %@";
|
||||||
|
"VoiceOver.Chat.AnimatedSticker" = "Animated sticker";
|
||||||
|
"VoiceOver.Chat.YourAnimatedSticker" = "Your animated sticker";
|
||||||
"VoiceOver.Chat.ContactFrom" = "Shared contact, from: %@";
|
"VoiceOver.Chat.ContactFrom" = "Shared contact, from: %@";
|
||||||
"VoiceOver.Chat.Contact" = "Shared contact";
|
"VoiceOver.Chat.Contact" = "Shared contact";
|
||||||
"VoiceOver.Chat.ContactPhoneNumberCount_1" = "%@ phone number";
|
"VoiceOver.Chat.ContactPhoneNumberCount_1" = "%@ phone number";
|
||||||
|
|||||||
@ -82,6 +82,7 @@ public class ContactsController: ViewController {
|
|||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
private var authorizationDisposable: Disposable?
|
private var authorizationDisposable: Disposable?
|
||||||
private let sortOrderPromise = Promise<ContactsSortOrder>()
|
private let sortOrderPromise = Promise<ContactsSortOrder>()
|
||||||
|
private let isInVoiceOver = ValuePromise<Bool>(false)
|
||||||
|
|
||||||
private var searchContentNode: NavigationBarSearchContentNode?
|
private var searchContentNode: NavigationBarSearchContentNode?
|
||||||
|
|
||||||
@ -117,6 +118,7 @@ public class ContactsController: ViewController {
|
|||||||
|
|
||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationAddIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.addPressed))
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationAddIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.addPressed))
|
||||||
|
self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.Contacts_VoiceOver_AddContact
|
||||||
|
|
||||||
self.scrollToTop = { [weak self] in
|
self.scrollToTop = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -199,11 +201,20 @@ public class ContactsController: ViewController {
|
|||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||||
if self.navigationItem.rightBarButtonItem != nil {
|
if self.navigationItem.rightBarButtonItem != nil {
|
||||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationAddIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.addPressed))
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationAddIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.addPressed))
|
||||||
|
self.navigationItem.rightBarButtonItem?.accessibilityLabel = self.presentationData.strings.Contacts_VoiceOver_AddContact
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = ContactsControllerNode(context: self.context, sortOrder: sortOrderPromise.get() |> distinctUntilChanged, present: { [weak self] c, a in
|
let sortOrderSignal: Signal<ContactsSortOrder, NoError> = combineLatest(self.sortOrderPromise.get(), self.isInVoiceOver.get())
|
||||||
|
|> map { sortOrder, isInVoiceOver in
|
||||||
|
if isInVoiceOver {
|
||||||
|
return .natural
|
||||||
|
} else {
|
||||||
|
return sortOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.displayNode = ContactsControllerNode(context: self.context, sortOrder: sortOrderSignal |> distinctUntilChanged, present: { [weak self] c, a in
|
||||||
self?.present(c, in: .window(.root), with: a)
|
self?.present(c, in: .window(.root), with: a)
|
||||||
}, controller: self)
|
}, controller: self)
|
||||||
self._ready.set(self.contactsNode.contactListNode.ready)
|
self._ready.set(self.contactsNode.contactListNode.ready)
|
||||||
@ -404,6 +415,8 @@ public class ContactsController: ViewController {
|
|||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
self.isInVoiceOver.set(layout.inVoiceOver)
|
||||||
|
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
|
|
||||||
self.contactsNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationInsetHeight, actualNavigationBarHeight: self.navigationHeight, transition: transition)
|
self.contactsNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationInsetHeight, actualNavigationBarHeight: self.navigationHeight, transition: transition)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -176,6 +176,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||||
|
|
||||||
|
private let messageAccessibilityArea: AccessibilityAreaNode
|
||||||
|
|
||||||
private var highlightedState: Bool = false
|
private var highlightedState: Bool = false
|
||||||
|
|
||||||
private var forceStopAnimations = false
|
private var forceStopAnimations = false
|
||||||
@ -199,6 +201,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
self.placeholderNode = StickerShimmerEffectNode()
|
self.placeholderNode = StickerShimmerEffectNode()
|
||||||
self.placeholderNode.isUserInteractionEnabled = false
|
self.placeholderNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.messageAccessibilityArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
super.init(layerBacked: false)
|
super.init(layerBacked: false)
|
||||||
|
|
||||||
self.containerNode.shouldBegin = { [weak self] location in
|
self.containerNode.shouldBegin = { [weak self] location in
|
||||||
@ -261,8 +265,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.placeholderNode)
|
self.contextSourceNode.contentNode.addSubnode(self.placeholderNode)
|
||||||
|
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
||||||
|
self.addSubnode(self.messageAccessibilityArea)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.focused = { [weak self] in
|
||||||
|
self?.accessibilityElementDidBecomeFocused()
|
||||||
|
}
|
||||||
|
|
||||||
self.dateAndStatusNode.openReactions = { [weak self] in
|
self.dateAndStatusNode.openReactions = { [weak self] in
|
||||||
guard let strongSelf = self, let item = strongSelf.item else {
|
guard let strongSelf = self, let item = strongSelf.item else {
|
||||||
@ -569,6 +577,37 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
|
||||||
|
super.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.accessibilityLabel = accessibilityData.label
|
||||||
|
self.messageAccessibilityArea.accessibilityValue = accessibilityData.value
|
||||||
|
self.messageAccessibilityArea.accessibilityHint = accessibilityData.hint
|
||||||
|
self.messageAccessibilityArea.accessibilityTraits = accessibilityData.traits
|
||||||
|
if let customActions = accessibilityData.customActions {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = customActions.map({ action -> UIAccessibilityCustomAction in
|
||||||
|
return ChatMessageAccessibilityCustomAction(name: action.name, target: self, selector: #selector(self.performLocalAccessibilityCustomAction(_:)), action: action.action)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func performLocalAccessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
|
||||||
|
if let action = action as? ChatMessageAccessibilityCustomAction {
|
||||||
|
switch action.action {
|
||||||
|
case .reply:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.setupReply(item.message.id)
|
||||||
|
}
|
||||||
|
case .options:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
||||||
let displaySize = CGSize(width: 184.0, height: 184.0)
|
let displaySize = CGSize(width: 184.0, height: 184.0)
|
||||||
let telegramFile = self.telegramFile
|
let telegramFile = self.telegramFile
|
||||||
@ -590,6 +629,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
let currentForwardInfo = self.appliedForwardInfo
|
let currentForwardInfo = self.appliedForwardInfo
|
||||||
|
|
||||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||||
|
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: nil)
|
||||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||||
var imageSize: CGSize = CGSize(width: 200.0, height: 200.0)
|
var imageSize: CGSize = CGSize(width: 200.0, height: 200.0)
|
||||||
@ -932,7 +972,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in
|
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
|
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
|
||||||
|
strongSelf.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
|
strongSelf.messageAccessibilityArea.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
|
|||||||
@ -488,9 +488,18 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
guard let strongSelf = self, let accessibilityData = strongSelf.accessibilityData else {
|
guard let strongSelf = self, let accessibilityData = strongSelf.accessibilityData else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for node in strongSelf.contentNodes {
|
||||||
|
if node.accessibilityActivate() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let singleUrl = accessibilityData.singleUrl {
|
if let singleUrl = accessibilityData.singleUrl {
|
||||||
strongSelf.item?.controllerInteraction.openUrl(singleUrl, false, false, strongSelf.item?.content.firstMessage)
|
strongSelf.item?.controllerInteraction.openUrl(singleUrl, false, false, strongSelf.item?.content.firstMessage)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,6 +54,11 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.buttonNode.addTarget(self, action: #selector(self.callButtonPressed), forControlEvents: .touchUpInside)
|
self.buttonNode.addTarget(self, action: #selector(self.callButtonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
self.callButtonPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,11 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
self.buttonPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,13 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
if let item = self.item {
|
||||||
|
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,13 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.requestMessageActionCallback(item.message.id, nil, true, false)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||||
|
|
||||||
|
private let messageAccessibilityArea: AccessibilityAreaNode
|
||||||
|
|
||||||
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
||||||
|
|
||||||
private var recognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
private var recognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
||||||
@ -64,6 +66,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
self.contextSourceNode = ContextExtractedContentContainingNode()
|
self.contextSourceNode = ContextExtractedContentContainingNode()
|
||||||
self.containerNode = ContextControllerSourceNode()
|
self.containerNode = ContextControllerSourceNode()
|
||||||
self.interactiveVideoNode = ChatMessageInteractiveInstantVideoNode()
|
self.interactiveVideoNode = ChatMessageInteractiveInstantVideoNode()
|
||||||
|
self.messageAccessibilityArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
super.init(layerBacked: false)
|
super.init(layerBacked: false)
|
||||||
|
|
||||||
@ -109,6 +112,19 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
|
||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.interactiveVideoNode)
|
self.contextSourceNode.contentNode.addSubnode(self.interactiveVideoNode)
|
||||||
|
self.addSubnode(self.messageAccessibilityArea)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.activate = { [weak self] in
|
||||||
|
guard let strongSelf = self, let accessibilityData = strongSelf.accessibilityData else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return strongSelf.interactiveVideoNode.accessibilityActivate()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.focused = { [weak self] in
|
||||||
|
self?.accessibilityElementDidBecomeFocused()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
@ -153,6 +169,37 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
self.view.addGestureRecognizer(replyRecognizer)
|
self.view.addGestureRecognizer(replyRecognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
|
||||||
|
super.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.accessibilityLabel = accessibilityData.label
|
||||||
|
self.messageAccessibilityArea.accessibilityValue = accessibilityData.value
|
||||||
|
self.messageAccessibilityArea.accessibilityHint = accessibilityData.hint
|
||||||
|
self.messageAccessibilityArea.accessibilityTraits = accessibilityData.traits
|
||||||
|
if let customActions = accessibilityData.customActions {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = customActions.map({ action -> UIAccessibilityCustomAction in
|
||||||
|
return ChatMessageAccessibilityCustomAction(name: action.name, target: self, selector: #selector(self.performLocalAccessibilityCustomAction(_:)), action: action.action)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func performLocalAccessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
|
||||||
|
if let action = action as? ChatMessageAccessibilityCustomAction {
|
||||||
|
switch action.action {
|
||||||
|
case .reply:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.setupReply(item.message.id)
|
||||||
|
}
|
||||||
|
case .options:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.interactiveVideoNode.frame, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
||||||
let layoutConstants = self.layoutConstants
|
let layoutConstants = self.layoutConstants
|
||||||
|
|
||||||
@ -172,6 +219,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
let currentForwardInfo = self.appliedForwardInfo
|
let currentForwardInfo = self.appliedForwardInfo
|
||||||
|
|
||||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||||
|
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: nil)
|
||||||
|
|
||||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||||
|
|
||||||
@ -449,10 +498,13 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
|
strongSelf.messageAccessibilityArea.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
|
|
||||||
strongSelf.appliedItem = item
|
strongSelf.appliedItem = item
|
||||||
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
|
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
|
||||||
|
|
||||||
|
strongSelf.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition
|
let transition: ContainedViewLayoutTransition
|
||||||
if animation.isAnimated {
|
if animation.isAnimated {
|
||||||
transition = .animated(duration: 0.2, curve: .spring)
|
transition = .animated(duration: 0.2, curve: .spring)
|
||||||
|
|||||||
@ -757,6 +757,11 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
self.progressPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func videoContentNode(at point: CGPoint) -> ASDisplayNode? {
|
func videoContentNode(at point: CGPoint) -> ASDisplayNode? {
|
||||||
if let videoFrame = self.videoFrame {
|
if let videoFrame = self.videoFrame {
|
||||||
if videoFrame.contains(point) {
|
if videoFrame.contains(point) {
|
||||||
|
|||||||
@ -144,7 +144,6 @@ private let voiceMessageDurationFormatter: DateComponentsFormatter = {
|
|||||||
let formatter = DateComponentsFormatter()
|
let formatter = DateComponentsFormatter()
|
||||||
formatter.unitsStyle = .spellOut
|
formatter.unitsStyle = .spellOut
|
||||||
formatter.allowedUnits = [.minute, .second]
|
formatter.allowedUnits = [.minute, .second]
|
||||||
formatter.zeroFormattingBehavior = .pad
|
|
||||||
return formatter
|
return formatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -152,7 +151,6 @@ private let musicDurationFormatter: DateComponentsFormatter = {
|
|||||||
let formatter = DateComponentsFormatter()
|
let formatter = DateComponentsFormatter()
|
||||||
formatter.unitsStyle = .spellOut
|
formatter.unitsStyle = .spellOut
|
||||||
formatter.allowedUnits = [.hour, .minute, .second]
|
formatter.allowedUnits = [.hour, .minute, .second]
|
||||||
formatter.zeroFormattingBehavior = .pad
|
|
||||||
return formatter
|
return formatter
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -232,6 +230,30 @@ final class ChatMessageAccessibilityData {
|
|||||||
var isSpecialFile = false
|
var isSpecialFile = false
|
||||||
for attribute in file.attributes {
|
for attribute in file.attributes {
|
||||||
switch attribute {
|
switch attribute {
|
||||||
|
case let .Sticker(displayText, packReference, _):
|
||||||
|
isSpecialFile = true
|
||||||
|
text = displayText
|
||||||
|
if file.mimeType == "application/x-tgsticker" {
|
||||||
|
if isIncoming {
|
||||||
|
if announceIncomingAuthors, let authorName = authorName {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_AnimatedStickerFrom(authorName).0
|
||||||
|
} else {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_AnimatedSticker
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_YourAnimatedSticker
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if isIncoming {
|
||||||
|
if announceIncomingAuthors, let authorName = authorName {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_StickerFrom(authorName).0
|
||||||
|
} else {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_Sticker
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = item.presentationData.strings.VoiceOver_Chat_YourSticker
|
||||||
|
}
|
||||||
|
}
|
||||||
case let .Audio(audio):
|
case let .Audio(audio):
|
||||||
isSpecialFile = true
|
isSpecialFile = true
|
||||||
if isSelected == nil {
|
if isSelected == nil {
|
||||||
|
|||||||
@ -43,6 +43,13 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
self.addSubnode(self.pinNode)
|
self.addSubnode(self.pinNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func accessibilityActivate() -> Bool {
|
||||||
|
if let item = self.item {
|
||||||
|
let _ = item.controllerInteraction.openMessage(item.message, .default)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||||
|
|
||||||
|
private let messageAccessibilityArea: AccessibilityAreaNode
|
||||||
|
|
||||||
private var highlightedState: Bool = false
|
private var highlightedState: Bool = false
|
||||||
|
|
||||||
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
private var currentSwipeToReplyTranslation: CGFloat = 0.0
|
||||||
@ -55,6 +57,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
self.placeholderNode = StickerShimmerEffectNode()
|
self.placeholderNode = StickerShimmerEffectNode()
|
||||||
self.placeholderNode.isUserInteractionEnabled = false
|
self.placeholderNode.isUserInteractionEnabled = false
|
||||||
self.dateAndStatusNode = ChatMessageDateAndStatusNode()
|
self.dateAndStatusNode = ChatMessageDateAndStatusNode()
|
||||||
|
self.messageAccessibilityArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
super.init(layerBacked: false)
|
super.init(layerBacked: false)
|
||||||
|
|
||||||
@ -120,6 +123,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
self.contextSourceNode.contentNode.addSubnode(self.placeholderNode)
|
self.contextSourceNode.contentNode.addSubnode(self.placeholderNode)
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
self.contextSourceNode.contentNode.addSubnode(self.imageNode)
|
||||||
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
self.contextSourceNode.contentNode.addSubnode(self.dateAndStatusNode)
|
||||||
|
self.addSubnode(self.messageAccessibilityArea)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.focused = { [weak self] in
|
||||||
|
self?.accessibilityElementDidBecomeFocused()
|
||||||
|
}
|
||||||
|
|
||||||
self.dateAndStatusNode.openReactions = { [weak self] in
|
self.dateAndStatusNode.openReactions = { [weak self] in
|
||||||
guard let strongSelf = self, let item = strongSelf.item else {
|
guard let strongSelf = self, let item = strongSelf.item else {
|
||||||
@ -238,6 +246,37 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
|
||||||
|
super.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
|
self.messageAccessibilityArea.accessibilityLabel = accessibilityData.label
|
||||||
|
self.messageAccessibilityArea.accessibilityValue = accessibilityData.value
|
||||||
|
self.messageAccessibilityArea.accessibilityHint = accessibilityData.hint
|
||||||
|
self.messageAccessibilityArea.accessibilityTraits = accessibilityData.traits
|
||||||
|
if let customActions = accessibilityData.customActions {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = customActions.map({ action -> UIAccessibilityCustomAction in
|
||||||
|
return ChatMessageAccessibilityCustomAction(name: action.name, target: self, selector: #selector(self.performLocalAccessibilityCustomAction(_:)), action: action.action)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.messageAccessibilityArea.accessibilityCustomActions = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func performLocalAccessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
|
||||||
|
if let action = action as? ChatMessageAccessibilityCustomAction {
|
||||||
|
switch action.action {
|
||||||
|
case .reply:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.setupReply(item.message.id)
|
||||||
|
}
|
||||||
|
case .options:
|
||||||
|
if let item = self.item {
|
||||||
|
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
|
||||||
let displaySize = CGSize(width: 184.0, height: 184.0)
|
let displaySize = CGSize(width: 184.0, height: 184.0)
|
||||||
let telegramFile = self.telegramFile
|
let telegramFile = self.telegramFile
|
||||||
@ -254,6 +293,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
let currentItem = self.item
|
let currentItem = self.item
|
||||||
|
|
||||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||||
|
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: nil)
|
||||||
|
|
||||||
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
let layoutConstants = chatMessageItemLayoutConstants(layoutConstants, params: params, presentationData: item.presentationData)
|
||||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||||
var imageSize: CGSize = CGSize(width: 100.0, height: 100.0)
|
var imageSize: CGSize = CGSize(width: 100.0, height: 100.0)
|
||||||
@ -598,6 +639,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
transition = .animated(duration: duration, curve: .spring)
|
transition = .animated(duration: duration, curve: .spring)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.updateAccessibilityData(accessibilityData)
|
||||||
|
|
||||||
transition.updateFrame(node: strongSelf.imageNode, frame: updatedImageFrame)
|
transition.updateFrame(node: strongSelf.imageNode, frame: updatedImageFrame)
|
||||||
imageApply()
|
imageApply()
|
||||||
|
|
||||||
@ -610,6 +653,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
strongSelf.placeholderNode.frame = placeholderFrame
|
strongSelf.placeholderNode.frame = placeholderFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.messageAccessibilityArea.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layoutSize)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user