diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 165ccc3dec..99a1e37548 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8906,3 +8906,5 @@ Sorry for the inconvenience."; "Gallery.VoiceOver.Edit" = "Edit"; "Gallery.VoiceOver.Stickers" = "Stickers"; "Gallery.VoiceOver.PictureInPicture" = "Picture-in-Picture"; + +"Appearance.VoiceOver.Theme" = "%@ Theme"; diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index bcca2e3b1f..ac8c8bf667 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -757,6 +757,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { self.scrollNode.view.delegate = self self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.showsVerticalScrollIndicator = false + + self.view.accessibilityTraits = .tabBar } @objc private func buttonPressed() { diff --git a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift index ad2d5de24b..66ad27a098 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift @@ -76,9 +76,7 @@ private final class ItemNode: ASDisplayNode { private var deleteButtonNode: ItemNodeDeleteButtonNode? private let buttonNode: HighlightTrackingButtonNode - - private let activateArea: AccessibilityAreaNode - + private var selectionFraction: CGFloat = 0.0 private(set) var unreadCount: Int = 0 @@ -140,13 +138,9 @@ private final class ItemNode: ASDisplayNode { self.badgeBackgroundInactiveNode.displayWithoutProcessing = true self.buttonNode = HighlightTrackingButtonNode() - - self.activateArea = AccessibilityAreaNode() - + super.init() - - self.isAccessibilityElement = true - + self.extractedContainerNode.contentNode.addSubnode(self.extractedBackgroundNode) self.extractedContainerNode.contentNode.addSubnode(self.titleContainer) self.titleContainer.addSubnode(self.titleNode) @@ -163,9 +157,7 @@ private final class ItemNode: ASDisplayNode { self.containerNode.addSubnode(self.extractedContainerNode) self.containerNode.targetNodeForActivationProgress = self.extractedContainerNode.contentNode self.addSubnode(self.containerNode) - - self.addSubnode(self.activateArea) - + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) self.containerNode.activated = { [weak self] gesture, _ in @@ -212,11 +204,16 @@ private final class ItemNode: ASDisplayNode { self.badgeBackgroundInactiveNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: presentationData.theme.chatList.unreadBadgeInactiveBackgroundColor) } - self.activateArea.accessibilityLabel = title + self.buttonNode.accessibilityLabel = title if unreadCount > 0 { - self.activateArea.accessibilityValue = strings.VoiceOver_Chat_UnreadMessages(Int32(unreadCount)) + self.buttonNode.accessibilityValue = strings.VoiceOver_Chat_UnreadMessages(Int32(unreadCount)) } else { - self.activateArea.accessibilityValue = "" + self.buttonNode.accessibilityValue = "" + } + if selectionFraction == 1.0 { + self.buttonNode.accessibilityTraits = [.button, .selected] + } else { + self.buttonNode.accessibilityTraits = [.button] } self.containerNode.isGestureEnabled = !isEditing && !isReordering @@ -338,7 +335,6 @@ private final class ItemNode: ASDisplayNode { self.extractedContainerNode.contentNode.frame = CGRect(origin: CGPoint(), size: size) self.extractedContainerNode.contentRect = CGRect(origin: CGPoint(x: self.extractedBackgroundNode.frame.minX, y: 0.0), size: CGSize(width:self.extractedBackgroundNode.frame.width, height: size.height)) self.containerNode.frame = CGRect(origin: CGPoint(), size: size) - self.activateArea.frame = CGRect(origin: CGPoint(), size: size) self.hitTestSlop = UIEdgeInsets(top: 0.0, left: -sideInset, bottom: 0.0, right: -sideInset) self.extractedContainerNode.hitTestSlop = self.hitTestSlop diff --git a/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift index 88e68b7335..25a99c9508 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift @@ -126,6 +126,13 @@ private final class ItemNode: ASDisplayNode { transition.updateAlpha(node: self.titleNode, alpha: deselectionAlpha) transition.updateAlpha(node: self.titleActiveNode, alpha: selectionAlpha) + self.buttonNode.accessibilityLabel = title + if selectionFraction == 1.0 { + self.buttonNode.accessibilityTraits = [.button, .selected] + } else { + self.buttonNode.accessibilityTraits = [.button] + } + if self.theme !== presentationData.theme { self.theme = presentationData.theme self.iconNode.image = icon diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 99c8479b81..39fa90802e 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1861,6 +1861,9 @@ public final class ChatListNode: ListView { return false } } + case .GroupReferenceEntry: + isEmpty = false + return true default: return true } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index b371c384a3..95f8de2fdd 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -686,9 +686,9 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState } else if case let .peerType(type) = mode, !result.isEmpty { switch type { case .group: - result.append(.AdditionalCategory(index: 0, id: 0, title: "Create a New Group for This", image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData)) + result.append(.AdditionalCategory(index: 0, id: 0, title: state.presentationData.strings.RequestPeer_CreateNewGroup, image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData)) case .channel: - result.append(.AdditionalCategory(index: 0, id: 0, title: "Create a New Channel for This", image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData)) + result.append(.AdditionalCategory(index: 0, id: 0, title: state.presentationData.strings.RequestPeer_CreateNewChannel, image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData)) default: break } diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift index 0e2ee1396e..3021294e44 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift @@ -103,7 +103,6 @@ public enum ChatInputMode: Equatable { public enum ChatTitlePanelContext: Equatable, Comparable { case pinnedMessage - case chatInfo case requestInProgress case toastAlert(String) case inviteRequests([EnginePeer], Int32) @@ -112,8 +111,6 @@ public enum ChatTitlePanelContext: Equatable, Comparable { switch self { case .pinnedMessage: return 0 - case .chatInfo: - return 1 case .requestInProgress: return 2 case .toastAlert: diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index 493722ee9a..0ac19f61d4 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -101,6 +101,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin self.isAccessibilityElement = true self.accessibilityLabel = item.text + self.accessibilityTraits = [.button] self.addSubnode(self.highlightBackgroundNode) self.addSubnode(self.titleLabelNode) diff --git a/submodules/Display/Source/AccessibilityAreaNode.swift b/submodules/Display/Source/AccessibilityAreaNode.swift index 0079f46e3a..5975b2fa31 100644 --- a/submodules/Display/Source/AccessibilityAreaNode.swift +++ b/submodules/Display/Source/AccessibilityAreaNode.swift @@ -8,6 +8,8 @@ public protocol AccessibilityFocusableNode { public final class AccessibilityAreaNode: ASDisplayNode { public var activate: (() -> Bool)? + public var increment: (() -> Void)? + public var decrement: (() -> Void)? public var focused: (() -> Void)? override public init() { @@ -43,4 +45,12 @@ public final class AccessibilityAreaNode: ASDisplayNode { } } } + + override public func accessibilityIncrement() { + self.increment?() + } + + override public func accessibilityDecrement() { + self.decrement?() + } } diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 7752442d25..fd839d4f14 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -697,9 +697,16 @@ open class NavigationBar: ASDisplayNode { if self.rightButtonNode.supernode != nil { addAccessibilityChildren(of: self.rightButtonNode, container: self, to: &accessibilityElements) } + if let customHeaderContentView = self.customHeaderContentView, customHeaderContentView.superview != nil { + customHeaderContentView.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(customHeaderContentView.bounds, in: customHeaderContentView) + accessibilityElements.append(customHeaderContentView) + } if let contentNode = self.contentNode { addAccessibilityChildren(of: contentNode, container: self, to: &accessibilityElements) } + if let secondaryContentNode = self.secondaryContentNode { + addAccessibilityChildren(of: secondaryContentNode, container: self, to: &accessibilityElements) + } return accessibilityElements } set(value) { } diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 4069f0fa68..20409a6720 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -528,4 +528,12 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture break } } + + open override func accessibilityPerformEscape() -> Bool { + if let controller = self.galleryController() { + controller.dismiss(animated: true) + return true + } + return false + } } diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h index 319a69076e..b72017d1e0 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h @@ -43,6 +43,12 @@ - (void)setValue:(CGFloat)value animated:(BOOL)animated; +- (void)increase; +- (void)increaseBy:(CGFloat)delta; + +- (void)decrease; +- (void)decreaseBy:(CGFloat)delta; + @end extern const CGFloat TGPhotoEditorSliderViewMargin; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m b/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m index 39154218cd..a9215a4c68 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m @@ -668,4 +668,32 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f; self.interactionEnded(); } +- (void)increase { + self.value = MIN(self.maximumValue, self.value + 1); + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + [self setNeedsLayout]; +} + +- (void)increaseBy:(CGFloat)delta { + self.value = MIN(self.maximumValue, self.value + delta); + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + [self setNeedsLayout]; +} + +- (void)decrease { + self.value = MAX(self.minimumValue, self.value - 1); + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + [self setNeedsLayout]; +} + +- (void)decreaseBy:(CGFloat)delta { + self.value = MAX(self.minimumValue, self.value - delta); + + [self sendActionsForControlEvents:UIControlEventValueChanged]; + [self setNeedsLayout]; +} + @end diff --git a/submodules/PremiumUI/Sources/HelloView.swift b/submodules/PremiumUI/Sources/HelloView.swift index f682a5cab7..41b06ae152 100644 --- a/submodules/PremiumUI/Sources/HelloView.swift +++ b/submodules/PremiumUI/Sources/HelloView.swift @@ -55,7 +55,7 @@ final class HelloView: UIView, PhoneDemoDecorationView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func setupAnimations() { guard self.activePhrases.isEmpty else { return @@ -121,11 +121,13 @@ final class HelloView: UIView, PhoneDemoDecorationView { self.activePositions.insert(positionIndex) let duration: Double = Double.random(in: 1.75...2.25) - view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view] _ in - self.activePhrases.remove(index) - self.activePositions.remove(positionIndex) - view?.removeFromSuperview() - self.spawnNextPhrase() + view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view, weak self] _ in + if let self { + self.activePhrases.remove(index) + self.activePositions.remove(positionIndex) + view?.removeFromSuperview() + self.spawnNextPhrase() + } }) view.layer.animateScale(from: CGFloat.random(in: 0.4 ..< 0.6), to: CGFloat.random(in: 0.9 ..< 1.2), duration: duration, removeOnCompletion: false) diff --git a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift index 1745f599e7..4f30925641 100644 --- a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift +++ b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift @@ -429,6 +429,9 @@ private final class BubbleSettingsToolbarNode: ASDisplayNode { super.init() + self.cancelButton.accessibilityTraits = [.button] + self.doneButton.accessibilityTraits = [.button] + self.addSubnode(self.switchItemNode) self.addSubnode(self.cornerRadiusItemNode) self.addSubnode(self.cancelButton) @@ -482,6 +485,9 @@ private final class BubbleSettingsToolbarNode: ASDisplayNode { self.cancelButton.setTitle(presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: []) self.doneButton.setTitle(presentationData.strings.Wallpaper_Set, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: []) + + self.cancelButton.accessibilityLabel = presentationData.strings.Common_Cancel + self.doneButton.accessibilityLabel = presentationData.strings.Wallpaper_Set } func updatePresentationThemeSettings(presentationThemeSettings: PresentationThemeSettings) { diff --git a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift index fc840584ef..51a0462c7f 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift @@ -95,6 +95,8 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { private let customTextNode: TextNode private var sliderView: TGPhotoEditorSliderView? + private let activateArea: AccessibilityAreaNode + private var item: AutodownloadDataUsagePickerItem? private var layoutParams: ListViewItemLayoutParams? @@ -126,12 +128,27 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { self.customTextNode.isUserInteractionEnabled = false self.customTextNode.displaysAsynchronously = false + self.activateArea = AccessibilityAreaNode() + super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.lowTextNode) self.addSubnode(self.mediumTextNode) self.addSubnode(self.highTextNode) self.addSubnode(self.customTextNode) + self.addSubnode(self.activateArea) + + self.activateArea.increment = { [weak self] in + if let self { + self.sliderView?.increase() + } + } + + self.activateArea.decrement = { [weak self] in + if let self { + self.sliderView?.decrease() + } + } } func updateSliderView() { @@ -154,6 +171,8 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { sliderView.isUserInteractionEnabled = item.enabled sliderView.alpha = item.enabled ? 1.0 : 0.4 sliderView.layer.allowsGroupOpacity = !item.enabled + + self.updateAccessibilityLabels() } } @@ -323,11 +342,33 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { strongSelf.updateSliderView() } + strongSelf.activateArea.accessibilityLabel = item.strings.AutoDownloadSettings_DataUsage + + strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height)) } }) } } + private func updateAccessibilityLabels() { + guard let item = self.item else { + return + } + var textNodes: [TextNode] = [self.lowTextNode, self.mediumTextNode, self.highTextNode] + if let customPosition = item.customPosition { + textNodes.insert(self.customTextNode, at: customPosition) + } + if let value = self.sliderView?.value { + self.activateArea.accessibilityValue = textNodes[Int(value)].cachedLayout?.attributedString?.string ?? "" + } + var accessibilityTraits: UIAccessibilityTraits = [.adjustable] + if item.enabled { + } else { + accessibilityTraits.insert(.notEnabled) + } + self.activateArea.accessibilityTraits = accessibilityTraits + } + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift index 84c9408aa7..0618ba3b71 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift @@ -135,6 +135,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { return self.containerNode } + private let activateArea: AccessibilityAreaNode + private var layoutParams: (ItemListWebsiteItem, ListViewItemLayoutParams, ItemListNeighbors)? private var editableControlNode: ItemListEditableControlNode? @@ -184,6 +186,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode.isLayerBacked = true + self.activateArea = AccessibilityAreaNode() + super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) self.addSubnode(self.containerNode) @@ -191,6 +195,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { self.containerNode.addSubnode(self.titleNode) self.containerNode.addSubnode(self.appNode) self.containerNode.addSubnode(self.locationNode) + + self.addSubnode(self.activateArea) } func asyncLayout() -> (_ item: ItemListWebsiteItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) { @@ -288,6 +294,28 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { if let strongSelf = self { strongSelf.layoutParams = (item, params, neighbors) + strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height)) + + strongSelf.activateArea.accessibilityLabel = titleAttributedString?.string ?? "" + + var value = "" + if let string = appAttributedString?.string { + value += string + } + if let string = locationAttributedString?.string { + if !value.isEmpty { + value += "\n" + } + value += string + } + strongSelf.activateArea.accessibilityValue = value + + if item.enabled { + strongSelf.activateArea.accessibilityTraits = [] + } else { + strongSelf.activateArea.accessibilityTraits = .notEnabled + } + if let _ = updatedTheme { strongSelf.topStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index ed7294f291..fca1b66abb 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -716,6 +716,9 @@ private final class TextSelectionToolbarNode: ASDisplayNode { super.init() + self.cancelButton.accessibilityTraits = [.button] + self.doneButton.accessibilityTraits = [.button] + self.addSubnode(self.switchItemNode) self.addSubnode(self.fontSizeItemNode) self.addSubnode(self.cancelButton) @@ -769,6 +772,9 @@ private final class TextSelectionToolbarNode: ASDisplayNode { self.cancelButton.setTitle(presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: []) self.doneButton.setTitle(presentationData.strings.Wallpaper_Set, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: []) + + self.cancelButton.accessibilityLabel = presentationData.strings.Common_Cancel + self.doneButton.accessibilityLabel = presentationData.strings.Wallpaper_Set } func updatePresentationThemeSettings(presentationThemeSettings: PresentationThemeSettings) { diff --git a/submodules/SettingsUI/Sources/ThemeCarouselItem.swift b/submodules/SettingsUI/Sources/ThemeCarouselItem.swift index a03e7dbd82..7b96c101e7 100644 --- a/submodules/SettingsUI/Sources/ThemeCarouselItem.swift +++ b/submodules/SettingsUI/Sources/ThemeCarouselItem.swift @@ -203,6 +203,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode { private var placeholderNode: StickerShimmerEffectNode var snapshotView: UIView? + private let activateAreaNode: AccessibilityAreaNode + var item: ThemeCarouselThemeIconItem? override var visibility: ListViewItemNodeVisibility { @@ -246,6 +248,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode { self.emojiImageNode = TransformImageNode() self.placeholderNode = StickerShimmerEffectNode() + + self.activateAreaNode = AccessibilityAreaNode() super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) @@ -272,6 +276,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode { } firstTime = false } + + self.addSubnode(self.activateAreaNode) } deinit { @@ -442,6 +448,16 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode { animatedStickerNode.frame = emojiFrame animatedStickerNode.updateLayout(size: emojiFrame.size) } + + let presentationData = item.context.sharedContext.currentPresentationData.with { $0 } + strongSelf.activateAreaNode.accessibilityLabel = item.themeReference.emoticon.flatMap { presentationData.strings.Appearance_VoiceOver_Theme($0).string } + if item.selected { + strongSelf.activateAreaNode.accessibilityTraits = [.button, .selected] + } else { + strongSelf.activateAreaNode.accessibilityTraits = [.button] + } + + strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: itemLayout.size) } }) } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsAppIconItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsAppIconItem.swift index 1175e83abb..b88e7e4a58 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsAppIconItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsAppIconItem.swift @@ -102,6 +102,8 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode { private let textNode: ImmediateTextNode private var action: (() -> Void)? + private let activateAreaNode: AccessibilityAreaNode + private var locked = false override init() { @@ -122,12 +124,16 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode { self.textNode.isUserInteractionEnabled = false self.textNode.displaysAsynchronously = false + self.activateAreaNode = AccessibilityAreaNode() + self.activateAreaNode.accessibilityTraits = [.button] + super.init() self.addSubnode(self.iconNode) self.addSubnode(self.overlayNode) self.addSubnode(self.textNode) self.addSubnode(self.lockNode) + self.addSubnode(self.activateAreaNode) } func setup(theme: PresentationTheme, icon: UIImage, title: NSAttributedString, locked: Bool, color: UIColor, bordered: Bool, selected: Bool, action: @escaping () -> Void) { @@ -140,6 +146,13 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode { action() } + self.activateAreaNode.accessibilityLabel = title.string + if locked { + self.activateAreaNode.accessibilityTraits = [.button, .notEnabled] + } else { + self.activateAreaNode.accessibilityTraits = [.button] + } + self.setNeedsLayout() } @@ -171,6 +184,8 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode { self.textNode.frame = textFrame self.lockNode.frame = CGRect(x: self.textNode.frame.minX - 10.0, y: 90.0, width: 6.0, height: 8.0) + + self.activateAreaNode.frame = self.bounds } } @@ -186,7 +201,7 @@ class ThemeSettingsAppIconItemNode: ListViewItemNode, ItemListItemNode { private let scrollNode: ASScrollNode private var nodes: [ThemeSettingsAppIconNode] = [] - + private var item: ThemeSettingsAppIconItem? private var layoutParams: ListViewItemLayoutParams? diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift index 81c8810792..6fa79773ef 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift @@ -207,6 +207,8 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { private let titleNode: TextNode var snapshotView: UIView? + private let activateAreaNode: AccessibilityAreaNode + var item: ThemeSettingsThemeIconItem? init() { @@ -222,13 +224,17 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { self.titleNode = TextNode() self.titleNode.isUserInteractionEnabled = false - + + self.activateAreaNode = AccessibilityAreaNode() + super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) self.addSubnode(self.containerNode) self.containerNode.addSubnode(self.imageNode) self.containerNode.addSubnode(self.overlayNode) self.containerNode.addSubnode(self.titleNode) + + self.addSubnode(self.activateAreaNode) self.containerNode.activated = { [weak self] gesture, _ in guard let strongSelf = self, let item = strongSelf.item else { @@ -308,6 +314,15 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { strongSelf.overlayNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 13.0), size: CGSize(width: 100.0, height: 64.0)) strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 88.0), size: CGSize(width: itemLayout.contentSize.width, height: 16.0)) + + strongSelf.activateAreaNode.accessibilityLabel = item.title + if item.selected { + strongSelf.activateAreaNode.accessibilityTraits = [.button, .selected] + } else { + strongSelf.activateAreaNode.accessibilityTraits = [.button] + } + + strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: itemLayout.size) } }) } diff --git a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift index c6a978ee6a..20a1310511 100644 --- a/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift +++ b/submodules/TelegramUI/Components/ChatListHeaderComponent/Sources/ChatListHeaderComponent.swift @@ -237,6 +237,9 @@ public final class ChatListHeaderComponent: Component { self.titleView.attributedText = NSAttributedString(string: title, font: Font.regular(17.0), textColor: theme.rootController.navigationBar.accentTextColor) let titleSize = self.titleView.updateLayout(CGSize(width: 100.0, height: 44.0)) + self.accessibilityLabel = title + self.accessibilityTraits = [.button] + if self.currentColor != theme.rootController.navigationBar.accentTextColor { self.currentColor = theme.rootController.navigationBar.accentTextColor self.arrowView.image = NavigationBarTheme.generateBackArrowImage(color: theme.rootController.navigationBar.accentTextColor) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 1fccb8b2b0..559552e153 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4304,36 +4304,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatTitleView = ChatTitleView(context: self.context, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: controllerInteraction.presentationContext.animationCache, animationRenderer: controllerInteraction.presentationContext.animationRenderer) self.navigationItem.titleView = self.chatTitleView - self.chatTitleView?.pressed = { [weak self] in - if let strongSelf = self { - if strongSelf.chatLocation == .peer(id: strongSelf.context.account.peerId) { - if let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) { - strongSelf.effectiveNavigationController?.pushViewController(infoController) - } - } else { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - return $0.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .chatInfo: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } else { - var updatedContexts = $0 - updatedContexts.append(.chatInfo) - return updatedContexts.sorted() - } - } - }) - } - } - } self.chatTitleView?.longPressed = { [weak self] in if let strongSelf = self, let peerView = strongSelf.peerView, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible { strongSelf.interfaceInteraction?.beginMessageSearch(.everything, "") @@ -8317,22 +8287,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: interactive, { current in - return current.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .chatInfo: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } else { - return $0 - } - }.updatedSearch(current.search == nil ? ChatSearchData(domain: domain).withUpdatedQuery(query) : current.search?.withUpdatedDomain(domain).withUpdatedQuery(query)) + return current.updatedSearch(current.search == nil ? ChatSearchData(domain: domain).withUpdatedQuery(query) : current.search?.withUpdatedDomain(domain).withUpdatedQuery(query)) }) strongSelf.updateItemNodesSearchTextHighlightStates() }) @@ -9613,17 +9568,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else { return } - strongSelf.updateChatPresentationInterfaceState(interactive: true, { state in - return state.updatedTitlePanelContext({ - $0.filter({ item in - if case .chatInfo = item { - return false - } else { - return true - } - }) - }) - }) let _ = (strongSelf.context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: .root) |> deliverOnMainQueue).start() }, openLinkEditing: { [weak self] in @@ -11070,30 +11014,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return interfaceState }).start() } - - override public func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - self.updateChatPresentationInterfaceState(animated: false, interactive: false, { - $0.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .chatInfo: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } else { - return $0 - } - } - }) - } - override public func viewWillLeaveNavigation() { self.chatDisplayNode.willNavigateAway() } @@ -11719,7 +11640,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private func navigationButtonAction(_ action: ChatNavigationButtonAction) { switch action { - case .spacer: + case .spacer, .toggleInfoPanel: break case .cancelMessageSelection: self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } }) @@ -12204,27 +12125,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .feed: break } - case .toggleInfoPanel: - self.updateChatPresentationInterfaceState(animated: true, interactive: true, { - return $0.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .chatInfo: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } else { - var updatedContexts = $0 - updatedContexts.append(.chatInfo) - return updatedContexts.sorted() - } - } - }) } } diff --git a/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift deleted file mode 100644 index 05b056aaee..0000000000 --- a/submodules/TelegramUI/Sources/ChatInfoTitlePanelNode.swift +++ /dev/null @@ -1,230 +0,0 @@ -import Foundation -import UIKit -import Display -import AsyncDisplayKit -import Postbox -import TelegramCore -import TelegramPresentationData -import ChatPresentationInterfaceState - -private enum ChatInfoTitleButton { - case search - case info - case mute - case unmute - case call - case report - case unarchive - - func title(_ strings: PresentationStrings) -> String { - switch self { - case .search: - return strings.Common_Search - case .info: - return strings.Conversation_Info - case .mute: - return strings.Conversation_TitleMute - case .unmute: - return strings.Conversation_TitleUnmute - case .call: - return strings.Conversation_Call - case .report: - return strings.ReportPeer_Report - case .unarchive: - return strings.ChatList_UnarchiveAction - } - } - - func icon(_ theme: PresentationTheme) -> UIImage? { - switch self { - case .search: - return PresentationResourcesChat.chatTitlePanelSearchImage(theme) - case .info: - return PresentationResourcesChat.chatTitlePanelInfoImage(theme) - case .mute: - return PresentationResourcesChat.chatTitlePanelMuteImage(theme) - case .unmute: - return PresentationResourcesChat.chatTitlePanelUnmuteImage(theme) - case .call: - return PresentationResourcesChat.chatTitlePanelCallImage(theme) - case .report: - return PresentationResourcesChat.chatTitlePanelReportImage(theme) - case .unarchive: - return PresentationResourcesChat.chatTitlePanelUnarchiveImage(theme) - } - } -} - -private func peerButtons(_ peer: Peer, interfaceState: ChatPresentationInterfaceState) -> [ChatInfoTitleButton] { - let muteAction: ChatInfoTitleButton - if interfaceState.peerIsMuted { - muteAction = .unmute - } else { - muteAction = .mute - } - - let infoButton: ChatInfoTitleButton - if interfaceState.isArchived { - infoButton = .unarchive - } else { - infoButton = .info - } - - if let peer = peer as? TelegramUser { - var buttons: [ChatInfoTitleButton] = [.search, muteAction] - if peer.botInfo == nil && interfaceState.callsAvailable { - buttons.append(.call) - } - - buttons.append(infoButton) - return buttons - } else if let _ = peer as? TelegramSecretChat { - var buttons: [ChatInfoTitleButton] = [.search, muteAction] - buttons.append(.call) - buttons.append(.info) - return buttons - } else if let channel = peer as? TelegramChannel { - if channel.flags.contains(.isCreator) || channel.addressName == nil { - return [.search, muteAction, infoButton] - } else { - return [.search, .report, muteAction, infoButton] - } - } else if let group = peer as? TelegramGroup { - if case .creator = group.role { - return [.search, muteAction, infoButton] - } else { - return [.search, muteAction, infoButton] - } - } else { - return [.search, muteAction, infoButton] - } -} - -private let buttonFont = Font.medium(10.0) - -private final class ChatInfoTitlePanelButtonNode: HighlightableButtonNode { - init() { - super.init() - - self.displaysAsynchronously = false - self.imageNode.displayWithoutProcessing = true - self.imageNode.displaysAsynchronously = false - - self.titleNode.displaysAsynchronously = false - - self.laysOutHorizontally = false - } - - func setup(text: String, color: UIColor, icon: UIImage?) { - self.setTitle(text, with: buttonFont, with: color, for: []) - self.setImage(icon, for: []) - if let icon = icon { - self.contentSpacing = max(0.0, 32.0 - icon.size.height) - } - } -} - -final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode { - private var theme: PresentationTheme? - - private let separatorNode: ASDisplayNode - private var buttons: [(ChatInfoTitleButton, ChatInfoTitlePanelButtonNode)] = [] - - override init() { - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - - super.init() - - self.addSubnode(self.separatorNode) - } - - override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { - let themeUpdated = self.theme !== interfaceState.theme - self.theme = interfaceState.theme - - let panelHeight: CGFloat = 55.0 - - if themeUpdated { - self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor - } - - let updatedButtons: [ChatInfoTitleButton] - switch interfaceState.chatLocation { - case .peer: - if let peer = interfaceState.renderedPeer?.peer { - updatedButtons = peerButtons(peer, interfaceState: interfaceState) - } else { - updatedButtons = [] - } - case .replyThread, .feed: - updatedButtons = [] - } - - var buttonsUpdated = false - if self.buttons.count != updatedButtons.count { - buttonsUpdated = true - } else { - for i in 0 ..< updatedButtons.count { - if self.buttons[i].0 != updatedButtons[i] { - buttonsUpdated = true - break - } - } - } - - if buttonsUpdated || themeUpdated { - for (_, buttonNode) in self.buttons { - buttonNode.removeFromSupernode() - } - self.buttons.removeAll() - for button in updatedButtons { - let buttonNode = ChatInfoTitlePanelButtonNode() - buttonNode.laysOutHorizontally = false - - buttonNode.setup(text: button.title(interfaceState.strings), color: interfaceState.theme.chat.inputPanel.panelControlAccentColor, icon: button.icon(interfaceState.theme)) - - buttonNode.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: [.touchUpInside]) - self.addSubnode(buttonNode) - self.buttons.append((button, buttonNode)) - } - } - - if !self.buttons.isEmpty { - let buttonWidth = floor((width - leftInset - rightInset) / CGFloat(self.buttons.count)) - var nextButtonOrigin: CGFloat = leftInset - for (_, buttonNode) in self.buttons { - buttonNode.frame = CGRect(origin: CGPoint(x: nextButtonOrigin, y: 0.0), size: CGSize(width: buttonWidth, height: panelHeight)) - nextButtonOrigin += buttonWidth - } - } - - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel))) - - return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) - } - - @objc func buttonPressed(_ node: HighlightableButtonNode) { - for (button, buttonNode) in self.buttons { - if buttonNode === node { - switch button { - case .info: - self.interfaceInteraction?.openPeerInfo() - case .mute: - self.interfaceInteraction?.togglePeerNotifications() - case .unmute: - self.interfaceInteraction?.togglePeerNotifications() - case .search: - self.interfaceInteraction?.beginMessageSearch(.everything, "") - case .call: - self.interfaceInteraction?.beginCall(false) - case .report: - self.interfaceInteraction?.reportPeer() - case .unarchive: - self.interfaceInteraction?.unarchiveChat() - } - break - } - } - } -} diff --git a/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift b/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift index eb4c315302..91eff93325 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift @@ -42,7 +42,7 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat break loop } } - case .chatInfo, .requestInProgress, .toastAlert, .inviteRequests: + case .requestInProgress, .toastAlert, .inviteRequests: selectedContext = context break loop } @@ -120,14 +120,6 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat panel.interfaceInteraction = interfaceInteraction return panel } - case .chatInfo: - if let currentPanel = currentPanel as? ChatInfoTitlePanelNode { - return currentPanel - } else { - let panel = ChatInfoTitlePanelNode() - panel.interfaceInteraction = interfaceInteraction - return panel - } case .requestInProgress: if let currentPanel = currentPanel as? ChatRequestInProgressTitlePanelNode { return currentPanel diff --git a/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift index 10e6c6ffcd..c0baac19b2 100644 --- a/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift @@ -119,6 +119,8 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode { private var avatarsContent: AnimatedAvatarSetContext.Content? private let avatarsNode: AnimatedAvatarSetNode + private let activateAreaNode: AccessibilityAreaNode + private var theme: PresentationTheme? private var peerId: PeerId? @@ -138,6 +140,9 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode { self.avatarsContext = AnimatedAvatarSetContext() self.avatarsNode = AnimatedAvatarSetNode() + self.activateAreaNode = AccessibilityAreaNode() + self.activateAreaNode.accessibilityTraits = .button + super.init() self.addSubnode(self.separatorNode) @@ -146,6 +151,8 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode { self.addSubnode(self.closeButton) self.addSubnode(self.avatarsNode) + + self.addSubnode(self.activateAreaNode) } @@ -198,6 +205,9 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode { transition.updateFrame(node: self.avatarsNode, frame: CGRect(origin: CGPoint(x: leftInset + 8.0, y: floor((panelHeight - avatarsSize.height) / 2.0)), size: avatarsSize)) } + self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) + self.activateAreaNode.accessibilityLabel = interfaceState.strings.Conversation_RequestsToJoin(self.count) + return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight) } diff --git a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift index 3c99188165..b716e487dc 100644 --- a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift @@ -9,6 +9,8 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { private let separatorNode: ASDisplayNode private let titleNode: ImmediateTextNode + private let activateAreaNode: AccessibilityAreaNode + private var theme: PresentationTheme? private var strings: PresentationStrings? @@ -19,10 +21,15 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 + self.activateAreaNode = AccessibilityAreaNode() + self.activateAreaNode.accessibilityTraits = .staticText + super.init() self.addSubnode(self.titleNode) self.addSubnode(self.separatorNode) + + self.addSubnode(self.activateAreaNode) } override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult { @@ -46,6 +53,9 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel))) + self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) + self.activateAreaNode.accessibilityLabel = interfaceState.strings.Channel_NotificationLoading + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } } diff --git a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift index 8e42a432af..5020093f6c 100644 --- a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift @@ -8,6 +8,8 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { private let separatorNode: ASDisplayNode private let titleNode: ImmediateTextNode + private let activateAreaNode: AccessibilityAreaNode + private var textColor: UIColor = .black { didSet { if !self.textColor.isEqual(oldValue) { @@ -34,6 +36,9 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { self.titleNode.maximumNumberOfLines = 1 self.titleNode.insets = UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0) + self.activateAreaNode = AccessibilityAreaNode() + self.activateAreaNode.accessibilityTraits = [.staticText] + super.init() self.addSubnode(self.titleNode) @@ -51,6 +56,9 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 20.0, height: 100.0)) self.titleNode.frame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize) + self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) + self.activateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? "" + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) } } diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index c43060353b..f586036edb 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -155,7 +155,12 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id) return .single(nil) } if #available(iOS 12.0, *) { - let baseLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode + var baseLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode + let rawSuffix = "-raw" + if baseLang.hasSuffix(rawSuffix) { + baseLang = String(baseLang.dropLast(rawSuffix.count)) + } + return context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) |> mapToSignal { sharedData in let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) ?? TranslationSettings.defaultSettings