Accessibility improvements

This commit is contained in:
Ilya Laktyushin 2023-02-07 16:21:02 +04:00
parent f1f4eefcbf
commit 050418b0b8
27 changed files with 299 additions and 45 deletions

View File

@ -8895,3 +8895,14 @@ Sorry for the inconvenience.";
"Premium.Purchase.OnlyOneSubscriptionAllowed" = "You have already purchased Telegram Premium for another account. You can only have one Telegram Premium subscription on one Apple ID.";
"Call.VoiceOver.Minimize" = "Minimize Call";
"Login.VoiceOver.PhoneCountryCode" = "Phone country code";
"Login.VoiceOver.PhoneNumber" = "Phone number";
"Login.VoiceOver.Password" = "Password";
"Gallery.VoiceOver.Delete" = "Delete";
"Gallery.VoiceOver.Fullscreen" = "Fullscreen";
"Gallery.VoiceOver.Share" = "Share";
"Gallery.VoiceOver.Edit" = "Edit";
"Gallery.VoiceOver.Stickers" = "Stickers";
"Gallery.VoiceOver.PictureInPicture" = "Picture-in-Picture";

View File

@ -894,6 +894,26 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
containerSize: CGSize(width: buttonWidth, height: buttonSize.height)
)
buttonTransition.setFrame(view: buttonView, frame: buttonFrame)
var accessibilityTitle = ""
switch type {
case .gallery:
accessibilityTitle = self.presentationData.strings.Attachment_Gallery
case .file:
accessibilityTitle = self.presentationData.strings.Attachment_File
case .location:
accessibilityTitle = self.presentationData.strings.Attachment_Location
case .contact:
accessibilityTitle = self.presentationData.strings.Attachment_Contact
case .poll:
accessibilityTitle = self.presentationData.strings.Attachment_Poll
case let .app(_, appName, _):
accessibilityTitle = appName
case .standalone:
accessibilityTitle = ""
}
buttonView.isAccessibilityElement = true
buttonView.accessibilityLabel = accessibilityTitle
buttonView.accessibilityTraits = [.button]
}
}

View File

@ -22,11 +22,14 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
private let animationNode: AnimatedStickerNode
private let titleNode: ImmediateTextNode
private let titleActivateAreaNode: AccessibilityAreaNode
private let titleIconNode: ASImageNode
private let currentOptionNode: ImmediateTextNode
private let currentOptionActivateAreaNode: AccessibilityAreaNode
private var dustNode: InvisibleInkDustNode?
private let currentOptionInfoNode: ASTextNode
private let currentOptionInfoActivateAreaNode: AccessibilityAreaNode
private let nextOptionTitleNode: ImmediateTextNode
private let nextOptionButtonNode: HighlightableButtonNode
@ -91,6 +94,9 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.titleNode.isUserInteractionEnabled = false
self.titleNode.displaysAsynchronously = false
self.titleActivateAreaNode = AccessibilityAreaNode()
self.titleActivateAreaNode.accessibilityTraits = .staticText
self.titleIconNode = ASImageNode()
self.titleIconNode.isLayerBacked = true
self.titleIconNode.displayWithoutProcessing = true
@ -102,10 +108,16 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.currentOptionNode.lineSpacing = 0.1
self.currentOptionNode.maximumNumberOfLines = 0
self.currentOptionActivateAreaNode = AccessibilityAreaNode()
self.currentOptionActivateAreaNode.accessibilityTraits = .staticText
self.currentOptionInfoNode = ASTextNode()
self.currentOptionInfoNode.isUserInteractionEnabled = false
self.currentOptionInfoNode.displaysAsynchronously = false
self.currentOptionInfoActivateAreaNode = AccessibilityAreaNode()
self.currentOptionInfoActivateAreaNode.accessibilityTraits = .staticText
self.nextOptionTitleNode = ImmediateTextNode()
self.nextOptionButtonNode = HighlightableButtonNode()
@ -113,6 +125,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: .sms(length: 5), nextType: .call, timeout: 60, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor)
self.nextOptionTitleNode.attributedText = nextOptionText
self.nextOptionButtonNode.isUserInteractionEnabled = nextOptionActive
self.nextOptionButtonNode.accessibilityLabel = nextOptionText.string
if nextOptionActive {
self.nextOptionButtonNode.accessibilityTraits = [.button]
} else {
self.nextOptionButtonNode.accessibilityTraits = [.button, .notEnabled]
}
self.nextOptionButtonNode.addSubnode(self.nextOptionTitleNode)
self.codeInputView = CodeInputView()
@ -156,8 +174,10 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.addSubnode(self.codeInputView)
self.addSubnode(self.titleNode)
self.addSubnode(self.titleActivateAreaNode)
self.addSubnode(self.titleIconNode)
self.addSubnode(self.currentOptionNode)
self.addSubnode(self.currentOptionActivateAreaNode)
self.addSubnode(self.currentOptionInfoNode)
self.addSubnode(self.nextOptionButtonNode)
self.addSubnode(self.animationNode)
@ -266,10 +286,18 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.appleSignInAllowed = appleSignInAllowed
self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, phoneNumber: self.phoneNumber, email: self.email, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor)
self.currentOptionActivateAreaNode.accessibilityLabel = self.currentOptionNode.attributedText?.string ?? ""
if case .missedCall = codeType {
self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.currentOptionInfoActivateAreaNode.accessibilityLabel = self.currentOptionInfoNode.attributedText?.string ?? ""
if self.currentOptionInfoActivateAreaNode.supernode == nil {
self.addSubnode(self.currentOptionInfoActivateAreaNode)
}
} else {
self.currentOptionInfoNode.attributedText = NSAttributedString(string: "", font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor)
if self.currentOptionInfoActivateAreaNode.supernode != nil {
self.currentOptionInfoActivateAreaNode.removeFromSupernode()
}
}
if let timeout = timeout {
#if DEBUG
@ -283,7 +311,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, timeout: strongSelf.currentTimeoutTime, strings: strongSelf.strings, primaryColor: strongSelf.theme.list.itemPrimaryTextColor, accentColor: strongSelf.theme.list.itemAccentColor)
strongSelf.nextOptionTitleNode.attributedText = nextOptionText
strongSelf.nextOptionButtonNode.isUserInteractionEnabled = nextOptionActive
strongSelf.nextOptionButtonNode.accessibilityLabel = nextOptionText.string
if nextOptionActive {
strongSelf.nextOptionButtonNode.accessibilityTraits = [.button]
} else {
strongSelf.nextOptionButtonNode.accessibilityTraits = [.button, .notEnabled]
}
if let layoutArguments = strongSelf.layoutArguments {
strongSelf.containerLayoutUpdated(layoutArguments.0, navigationBarHeight: layoutArguments.1, transition: .immediate)
}
@ -301,7 +334,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
let (nextOptionText, nextOptionActive) = authorizationNextOptionText(currentType: codeType, nextType: nextType, timeout: self.currentTimeoutTime, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor)
self.nextOptionTitleNode.attributedText = nextOptionText
self.nextOptionButtonNode.isUserInteractionEnabled = nextOptionActive
self.nextOptionButtonNode.accessibilityLabel = nextOptionText.string
if nextOptionActive {
self.nextOptionButtonNode.accessibilityTraits = [.button]
} else {
self.nextOptionButtonNode.accessibilityTraits = [.button, .notEnabled]
}
if let layoutArguments = self.layoutArguments {
self.containerLayoutUpdated(layoutArguments.0, navigationBarHeight: layoutArguments.1, transition: .immediate)
}
@ -347,6 +385,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeTelegramTitle, font: Font.semibold(40.0), textColor: self.theme.list.itemPrimaryTextColor)
}
self.titleActivateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? ""
if let inputHeight = layout.inputHeight {
if let codeType = self.codeType, case .email = codeType {
insets.bottom = max(inputHeight, insets.bottom)
@ -525,6 +565,10 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
}
self.nextOptionTitleNode.frame = self.nextOptionButtonNode.bounds
self.titleActivateAreaNode.frame = self.titleNode.frame
self.currentOptionActivateAreaNode.frame = self.currentOptionNode.frame
self.currentOptionInfoActivateAreaNode.frame = self.currentOptionInfoNode.frame
}
func activateInput() {

View File

@ -15,7 +15,9 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
private let animationNode: AnimatedStickerNode
private let titleNode: ASTextNode
private let titleActivateAreaNode: AccessibilityAreaNode
private let noticeNode: ASTextNode
private let noticeActivateAreaNode: AccessibilityAreaNode
private let forgotNode: HighlightableButtonNode
private let resetNode: HighlightableButtonNode
private let proceedNode: SolidRoundedButtonNode
@ -68,15 +70,23 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
self.titleNode.displaysAsynchronously = false
self.titleNode.attributedText = NSAttributedString(string: strings.LoginPassword_Title, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
self.titleActivateAreaNode = AccessibilityAreaNode()
self.titleActivateAreaNode.accessibilityTraits = .staticText
self.noticeNode = ASTextNode()
self.noticeNode.isUserInteractionEnabled = false
self.noticeNode.displaysAsynchronously = false
self.noticeNode.lineSpacing = 0.1
self.noticeNode.attributedText = NSAttributedString(string: strings.TwoStepAuth_EnterPasswordHelp, font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.noticeActivateAreaNode = AccessibilityAreaNode()
self.noticeActivateAreaNode.accessibilityTraits = .staticText
self.forgotNode = HighlightableButtonNode()
self.forgotNode.displaysAsynchronously = false
self.forgotNode.setAttributedTitle(NSAttributedString(string: self.strings.TwoStepAuth_EnterPasswordForgot, font: Font.regular(16.0), textColor: self.theme.list.itemAccentColor, paragraphAlignment: .center), for: [])
self.forgotNode.accessibilityLabel = self.strings.TwoStepAuth_EnterPasswordForgot
self.forgotNode.accessibilityTraits = [.button]
self.resetNode = HighlightableButtonNode()
self.resetNode.displaysAsynchronously = false
@ -95,6 +105,7 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
self.codeField.textField.tintColor = self.theme.list.itemAccentColor
self.codeField.textField.accessibilityHint = self.strings.Login_VoiceOver_Password
self.proceedNode = SolidRoundedButtonNode(title: self.strings.Login_Continue, theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false)
self.proceedNode.progressType = .embedded
@ -114,9 +125,11 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
self.addSubnode(self.codeSeparatorNode)
self.addSubnode(self.codeField)
self.addSubnode(self.titleNode)
self.addSubnode(self.titleActivateAreaNode)
self.addSubnode(self.forgotNode)
self.addSubnode(self.resetNode)
self.addSubnode(self.noticeNode)
self.addSubnode(self.noticeActivateAreaNode)
self.addSubnode(self.animationNode)
self.addSubnode(self.proceedNode)
@ -214,6 +227,12 @@ final class AuthorizationSequencePasswordEntryControllerNode: ASDisplayNode, UIT
self.animationNode.updateLayout(size: animationSize)
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - additionalBottomInset)), items: items, transition: transition, failIfDoesNotFit: false)
self.titleActivateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? ""
self.noticeActivateAreaNode.accessibilityLabel = self.noticeNode.attributedText?.string ?? ""
self.titleActivateAreaNode.frame = self.titleNode.frame
self.noticeActivateAreaNode.frame = self.noticeNode.frame
}
func activateInput() {

View File

@ -110,6 +110,8 @@ private final class PhoneAndCountryNode: ASDisplayNode {
self.phoneInputNode.numberField.textField.textColor = theme.list.itemPrimaryTextColor
self.phoneInputNode.countryCodeField.textField.tintColor = theme.list.itemAccentColor
self.phoneInputNode.numberField.textField.tintColor = theme.list.itemAccentColor
self.phoneInputNode.countryCodeField.accessibilityHint = strings.Login_VoiceOver_PhoneCountryCode
self.phoneInputNode.numberField.accessibilityHint = strings.Login_VoiceOver_PhoneNumber
self.phoneInputNode.countryCodeField.textField.tintColor = theme.list.itemAccentColor
self.phoneInputNode.numberField.textField.tintColor = theme.list.itemAccentColor
@ -172,6 +174,9 @@ private final class PhoneAndCountryNode: ASDisplayNode {
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
}
strongSelf.countryButton.accessibilityLabel = strongSelf.countryButton.attributedTitle(for: .normal)?.string ?? ""
strongSelf.countryButton.accessibilityTraits = [.button]
if strongSelf.hasCountry {
strongSelf.hasNumberUpdated?(!strongSelf.phoneInputNode.codeAndNumber.2.isEmpty)
} else {
@ -289,7 +294,9 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
private let animationNode: AnimatedStickerNode
private let managedAnimationNode: ManagedPhoneAnimationNode
private let titleNode: ASTextNode
private let titleActivateAreaNode: AccessibilityAreaNode
private let noticeNode: ASTextNode
private let noticeActivateAreaNode: AccessibilityAreaNode
private let phoneAndCountryNode: PhoneAndCountryNode
private let contactSyncNode: ContactSyncNode
private let proceedNode: SolidRoundedButtonNode
@ -378,12 +385,18 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.titleNode.displaysAsynchronously = false
self.titleNode.attributedText = NSAttributedString(string: account == nil ? strings.Login_NewNumber : strings.Login_PhoneTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor)
self.titleActivateAreaNode = AccessibilityAreaNode()
self.titleActivateAreaNode.accessibilityTraits = .staticText
self.noticeNode = ASTextNode()
self.noticeNode.maximumNumberOfLines = 0
self.noticeNode.isUserInteractionEnabled = true
self.noticeNode.displaysAsynchronously = false
self.noticeNode.lineSpacing = 0.1
self.noticeActivateAreaNode = AccessibilityAreaNode()
self.noticeActivateAreaNode.accessibilityTraits = .staticText
self.noticeNode.attributedText = NSAttributedString(string: account == nil ? strings.ChangePhoneNumberNumber_Help : strings.Login_PhoneAndCountryHelp, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.contactSyncNode = ContactSyncNode(theme: theme, strings: strings)
@ -404,6 +417,8 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.addSubnode(self.titleNode)
self.addSubnode(self.noticeNode)
self.addSubnode(self.titleActivateAreaNode)
self.addSubnode(self.noticeActivateAreaNode)
self.addSubnode(self.phoneAndCountryNode)
self.addSubnode(self.contactSyncNode)
self.addSubnode(self.proceedNode)
@ -534,6 +549,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
let additionalBottomInset: CGFloat = layout.size.width > 320.0 ? 80.0 : 10.0
self.titleNode.attributedText = NSAttributedString(string: self.account == nil ? strings.Login_NewNumber : strings.Login_PhoneTitle, font: Font.bold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
self.titleActivateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? ""
let inset: CGFloat = 24.0
let maximumWidth: CGFloat = min(430.0, layout.size.width)
@ -587,6 +603,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - additionalBottomInset)), items: items, transition: transition, failIfDoesNotFit: false)
transition.updateFrame(node: self.managedAnimationNode, frame: self.animationNode.frame)
self.titleActivateAreaNode.frame = self.titleNode.frame
self.noticeActivateAreaNode.accessibilityLabel = self.noticeNode.attributedText?.string ?? ""
self.noticeActivateAreaNode.frame = self.noticeNode.frame
}
func activateInput() {
@ -726,6 +746,7 @@ final class PhoneConfirmationController: ViewController {
class Node: ASDisplayNode {
private let theme: PresentationTheme
private let strings: PresentationStrings
private let code: String
private let number: String
@ -740,6 +761,7 @@ final class PhoneConfirmationController: ViewController {
private let phoneTargetNode: ImmediateTextNode
private let textNode: ImmediateTextNode
private let textActivateAreaNode: AccessibilityAreaNode
private let cancelButton: HighlightableButtonNode
fileprivate let proceedNode: SolidRoundedButtonNode
@ -751,6 +773,7 @@ final class PhoneConfirmationController: ViewController {
init(theme: PresentationTheme, strings: PresentationStrings, code: String, number: String) {
self.theme = theme
self.strings = strings
self.code = code
self.number = number
@ -767,8 +790,13 @@ final class PhoneConfirmationController: ViewController {
self.textNode.attributedText = NSAttributedString(string: strings.Login_PhoneNumberConfirmation, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor)
self.textNode.textAlignment = .center
self.textActivateAreaNode = AccessibilityAreaNode()
self.textActivateAreaNode.accessibilityTraits = .staticText
self.cancelButton = HighlightableButtonNode()
self.cancelButton.setTitle(strings.Login_Edit, with: Font.regular(19.0), with: theme.list.itemAccentColor, for: .normal)
self.cancelButton.accessibilityTraits = [.button]
self.cancelButton.accessibilityLabel = strings.Login_Edit
self.proceedNode = SolidRoundedButtonNode(title: strings.Login_Continue, theme: SolidRoundedButtonTheme(theme: theme), height: 50.0, cornerRadius: 11.0, gloss: false)
self.proceedNode.progressType = .embedded
@ -814,6 +842,7 @@ final class PhoneConfirmationController: ViewController {
self.addSubnode(self.phoneTargetNode)
self.addSubnode(self.textNode)
self.addSubnode(self.textActivateAreaNode)
self.addSubnode(self.cancelButton)
self.addSubnode(self.proceedNode)
@ -1009,6 +1038,8 @@ final class PhoneConfirmationController: ViewController {
let textSize = self.textNode.updateLayout(backgroundSize)
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - textSize.width) / 2.0), y: 88.0), size: textSize).offsetBy(dx: backgroundFrame.minX, dy: backgroundFrame.minY))
self.textActivateAreaNode.frame = self.textNode.frame
self.textActivateAreaNode.accessibilityLabel = "\(self.code) \(self.number). \(self.strings.Login_PhoneNumberConfirmation)"
let proceedWidth = backgroundSize.width - 16.0 * 2.0
let proceedHeight = self.proceedNode.updateLayout(width: proceedWidth, transition: transition)

View File

@ -196,7 +196,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
}
return ContactsPeerItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
sortOrder: nameSortOrder,
displayOrder: nameDisplayOrder,
context: context,

View File

@ -319,7 +319,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
}
}
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
context: context,
title: title,
image: image,
@ -525,7 +525,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
}
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
sortOrder: presentationData.nameSortOrder,
displayOrder: presentationData.nameDisplayOrder,
context: context,
@ -564,7 +564,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
let status: ContactsPeerItemStatus = .none
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
sortOrder: presentationData.nameSortOrder,
displayOrder: presentationData.nameDisplayOrder,
context: context,
@ -778,7 +778,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
}
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
sortOrder: presentationData.nameSortOrder,
displayOrder: presentationData.nameDisplayOrder,
context: context,
@ -817,7 +817,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
let status: ContactsPeerItemStatus = .none
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
sortOrder: presentationData.nameSortOrder,
displayOrder: presentationData.nameDisplayOrder,
context: context,
@ -887,7 +887,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
}
}
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings),
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder),
context: context,
title: title,
image: image,

View File

@ -64,7 +64,7 @@ func localizedCountryNamesAndCodes(strings: PresentationStrings) -> [((String, S
let locale = localeWithStrings(strings)
var result: [((String, String), String, [Int])] = []
for country in AuthorizationSequenceCountrySelectionController.countries() {
if country.hidden {
if country.hidden || country.id == "FT" {
continue
}
if let englishCountryName = usEnglishLocale.localizedString(forRegionCode: country.id), let countryName = locale.localizedString(forRegionCode: country.id) {
@ -362,20 +362,24 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
}
var countryName: String
var cleanCountryName: String
let originalCountryName: String
let code: String
if tableView === self.tableView {
countryName = self.sections[indexPath.section].1[indexPath.row].0.1
countryName = "\(emojiFlagForISOCountryCode(self.sections[indexPath.section].1[indexPath.row].1)) \(countryName)"
cleanCountryName = self.sections[indexPath.section].1[indexPath.row].0.1
countryName = "\(emojiFlagForISOCountryCode(self.sections[indexPath.section].1[indexPath.row].1)) \(cleanCountryName)"
originalCountryName = self.sections[indexPath.section].1[indexPath.row].0.0
code = "+\(self.sections[indexPath.section].1[indexPath.row].2)"
} else {
countryName = self.searchResults[indexPath.row].0.1
countryName = "\(emojiFlagForISOCountryCode(self.searchResults[indexPath.row].1)) \(countryName)"
cleanCountryName = self.searchResults[indexPath.row].0.1
countryName = "\(emojiFlagForISOCountryCode(self.searchResults[indexPath.row].1)) \(cleanCountryName)"
originalCountryName = self.searchResults[indexPath.row].0.0
code = "+\(self.searchResults[indexPath.row].2)"
}
cell.accessibilityLabel = cleanCountryName
cell.accessibilityValue = code
cell.textLabel?.text = countryName
cell.detailTextLabel?.text = originalCountryName
if self.displayCodes, let label = cell.accessoryView as? UILabel {

View File

@ -48,7 +48,9 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
if _image == nil {
self.item?.accessibilityLabel = value
if self.item?.accessibilityLabel == nil {
self.item?.accessibilityLabel = value
}
}
}
}

View File

@ -341,6 +341,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.authorNameNode.maximumNumberOfLines = 1
self.authorNameNode.isUserInteractionEnabled = false
self.authorNameNode.displaysAsynchronously = false
self.dateNode = ASTextNode()
self.dateNode.maximumNumberOfLines = 1
self.dateNode.isUserInteractionEnabled = false
@ -428,9 +429,20 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.contentNode.addSubnode(self.statusButtonNode)
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), for: [.touchUpInside])
self.deleteButton.accessibilityTraits = [.button]
self.deleteButton.accessibilityLabel = presentationData.strings.Gallery_VoiceOver_Delete
self.fullscreenButton.addTarget(self, action: #selector(self.fullscreenButtonPressed), for: [.touchUpInside])
self.fullscreenButton.accessibilityTraits = [.button]
self.fullscreenButton.accessibilityLabel = presentationData.strings.Gallery_VoiceOver_Fullscreen
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), for: [.touchUpInside])
self.actionButton.accessibilityTraits = [.button]
self.actionButton.accessibilityLabel = presentationData.strings.Gallery_VoiceOver_Share
self.editButton.addTarget(self, action: #selector(self.editButtonPressed), for: [.touchUpInside])
self.editButton.accessibilityTraits = [.button]
self.editButton.accessibilityLabel = presentationData.strings.Gallery_VoiceOver_Edit
self.backwardButton.addTarget(self, action: #selector(self.backwardButtonPressed), forControlEvents: .touchUpInside)
self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
@ -595,12 +607,15 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
} else {
self.authorNameNode.attributedText = nil
}
self.authorNameNode.accessibilityLabel = self.authorNameNode.attributedText?.string
if let dateText = dateText {
self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: .white)
} else {
self.dateNode.attributedText = nil
}
self.dateNode.accessibilityLabel = self.dateNode.attributedText?.string
self.requestLayout?(.immediate)
}
@ -763,8 +778,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
} else {
self.authorNameNode.attributedText = nil
}
self.authorNameNode.accessibilityLabel = self.authorNameNode.attributedText?.string
self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: .white)
self.dateNode.accessibilityLabel = self.dateNode.attributedText?.string
if canFullscreen {
self.fullscreenButton.isHidden = false
self.deleteButton.isHidden = true

View File

@ -443,10 +443,12 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
var barButtonItems: [UIBarButtonItem] = []
if imageReference.media.flags.contains(.hasStickers) {
let rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/Stickers"), color: .white), style: .plain, target: self, action: #selector(self.openStickersButtonPressed))
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.Gallery_VoiceOver_Stickers
barButtonItems.append(rightBarButtonItem)
}
if self.message != nil {
let moreMenuItem = UIBarButtonItem(customDisplayNode: self.moreBarButton)!
moreMenuItem.accessibilityLabel = self.presentationData.strings.Common_More
barButtonItems.append(moreMenuItem)
}
self._rightBarButtonItems.set(.single(barButtonItems))
@ -646,6 +648,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
var barButtonItems: [UIBarButtonItem] = []
if self.message != nil {
let moreMenuItem = UIBarButtonItem(customDisplayNode: self.moreBarButton)!
moreMenuItem.accessibilityLabel = self.presentationData.strings.Common_More
barButtonItems.append(moreMenuItem)
}
self._rightBarButtonItems.set(.single(barButtonItems))

View File

@ -1420,10 +1420,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var barButtonItems: [UIBarButtonItem] = []
if hasLinkedStickers {
let rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/Stickers"), color: .white), style: .plain, target: self, action: #selector(self.openStickersButtonPressed))
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.Gallery_VoiceOver_Stickers
barButtonItems.append(rightBarButtonItem)
}
if forceEnablePiP || (!isAnimated && !disablePlayerControls && !disablePictureInPicture) {
let rightBarButtonItem = UIBarButtonItem(image: pictureInPictureButtonImage, style: .plain, target: self, action: #selector(self.pictureInPictureButtonPressed))
rightBarButtonItem.accessibilityLabel = self.presentationData.strings.Gallery_VoiceOver_PictureInPicture
self.pictureInPictureButton = rightBarButtonItem
barButtonItems.append(rightBarButtonItem)
self.hasPictureInPicture = true
@ -1452,6 +1454,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if hasMoreButton {
let moreMenuItem = UIBarButtonItem(customDisplayNode: self.moreBarButton)!
moreMenuItem.accessibilityLabel = self.presentationData.strings.Common_More
barButtonItems.append(moreMenuItem)
}
}

View File

@ -159,11 +159,13 @@ public final class ItemListPresentationData: Equatable {
public let theme: PresentationTheme
public let fontSize: PresentationFontSize
public let strings: PresentationStrings
public let nameDisplayOrder: PresentationPersonNameOrder
public init(theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings) {
public init(theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) {
self.theme = theme
self.fontSize = fontSize
self.strings = strings
self.nameDisplayOrder = nameDisplayOrder
}
public static func ==(lhs: ItemListPresentationData, rhs: ItemListPresentationData) -> Bool {
@ -176,6 +178,9 @@ public final class ItemListPresentationData: Equatable {
if lhs.fontSize != rhs.fontSize {
return false
}
if lhs.nameDisplayOrder != rhs.nameDisplayOrder {
return false
}
return true
}
}
@ -226,6 +231,6 @@ public extension PresentationFontSize {
public extension ItemListPresentationData {
convenience init(_ presentationData: PresentationData) {
self.init(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings)
self.init(theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder)
}
}

View File

@ -232,15 +232,20 @@ public class ItemListCallListItemNode: ListViewItemNode {
insets = UIEdgeInsets()
}
var accessibilityText = ""
let earliestMessage = item.messages.sorted(by: {$0.timestamp < $1.timestamp}).first!
let titleText = stringForDate(timestamp: earliestMessage.timestamp, strings: item.presentationData.strings)
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: titleText, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
accessibilityText.append(titleText)
accessibilityText.append(". ")
contentHeight += titleLayout.size.height + 18.0
var index = 0
var nodesLayout: [(TextNodeLayout, TextNodeLayout)] = []
var nodesApply: [(() -> TextNode, () -> TextNode)] = []
for message in item.messages {
let makeTimeLayout = makeNodesLayout[index].0
let time = stringForMessageTimestamp(timestamp: message.timestamp, dateTimeFormat: item.dateTimeFormat)
@ -250,6 +255,8 @@ public class ItemListCallListItemNode: ListViewItemNode {
let type = stringForCallType(message: message, strings: item.presentationData.strings)
let (typeLayout, typeApply) = makeTypeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: type, font: typeFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - leftInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
accessibilityText.append("\(time) - \(type)")
nodesLayout.append((timeLayout, typeLayout))
nodesApply.append((timeApply, typeApply))
@ -336,6 +343,8 @@ public class ItemListCallListItemNode: ListViewItemNode {
index += 1
}
strongSelf.accessibilityArea.accessibilityLabel = accessibilityText
strongSelf.accessibilityArea.accessibilityTraits = .staticText
strongSelf.accessibilityArea.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
}
})

View File

@ -101,6 +101,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
if self.isEnabled != oldValue {
self.updateColors(animated: true)
}
self.updateAccessibilityLabels()
}
}
@ -130,6 +131,11 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
private func updateAccessibilityLabels() {
self.accessibilityLabel = (self.title ?? "") + " " + (self.subtitle ?? "")
if !self.isEnabled {
self.accessibilityTraits = [.button, .notEnabled]
} else {
self.accessibilityTraits = [.button]
}
}
private var animationTimer: SwiftSignalKit.Timer?
@ -289,6 +295,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
}
}
}
self.updateAccessibilityLabels()
}
public override func didLoad() {
@ -795,6 +803,11 @@ public final class SolidRoundedButtonView: UIView {
private func updateAccessibilityLabels() {
self.accessibilityLabel = (self.title ?? "") + " " + (self.subtitle ?? "")
self.accessibilityValue = self.label
if !self.isEnabled {
self.accessibilityTraits = [.button, .notEnabled]
} else {
self.accessibilityTraits = [.button]
}
}
public var icon: UIImage? {
@ -808,6 +821,7 @@ public final class SolidRoundedButtonView: UIView {
if self.isEnabled != oldValue {
self.titleNode.alpha = self.isEnabled ? 1.0 : 0.6
}
self.updateAccessibilityLabels()
}
}
@ -976,6 +990,8 @@ public final class SolidRoundedButtonView: UIView {
if #available(iOS 13.0, *) {
self.buttonBackgroundNode.layer.cornerCurve = .continuous
}
self.updateAccessibilityLabels()
}
required public init(coder: NSCoder) {

View File

@ -214,6 +214,7 @@ final class ChatMessageAccessibilityData {
loop: for media in message.media {
if let _ = media as? TelegramMediaImage {
traits.insert(.image)
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_PhotoFrom(authorName).string

View File

@ -32,6 +32,8 @@ final class ChatTextInputAudioRecordingCancelIndicator: ASDisplayNode {
self.cancelButton = HighlightableButtonNode()
self.cancelButton.setTitle(strings.Common_Cancel, with: cancelFont, with: theme.chat.inputPanel.panelControlAccentColor, for: [])
self.cancelButton.alpha = 0.0
self.cancelButton.accessibilityLabel = strings.Common_Cancel
self.cancelButton.accessibilityTraits = [.button]
self.strings = strings

View File

@ -10,6 +10,7 @@ import MergeLists
import AccountContext
import ChatPresentationInterfaceState
import ChatControllerInteraction
import ItemListUI
private struct CommandChatInputContextPanelEntryStableId: Hashable {
let command: PeerCommand
@ -36,8 +37,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
return lhs.index < rhs.index
}
func item(context: AccountContext, fontSize: PresentationFontSize, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> ListViewItem {
return CommandChatInputPanelItem(context: context, theme: self.theme, fontSize: fontSize, command: self.command, commandSelected: commandSelected)
func item(context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> ListViewItem {
return CommandChatInputPanelItem(context: context, presentationData: ItemListPresentationData(presentationData), command: self.command, commandSelected: commandSelected)
}
}
@ -47,12 +48,12 @@ private struct CommandChatInputContextPanelTransition {
let updates: [ListViewUpdateItem]
}
private func preparedTransition(from fromEntries: [CommandChatInputContextPanelEntry], to toEntries: [CommandChatInputContextPanelEntry], context: AccountContext, fontSize: PresentationFontSize, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> CommandChatInputContextPanelTransition {
private func preparedTransition(from fromEntries: [CommandChatInputContextPanelEntry], to toEntries: [CommandChatInputContextPanelEntry], context: AccountContext, presentationData: PresentationData, commandSelected: @escaping (PeerCommand, Bool) -> Void) -> CommandChatInputContextPanelTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, fontSize: fontSize, commandSelected: commandSelected), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, fontSize: fontSize, commandSelected: commandSelected), directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, commandSelected: commandSelected), directionHint: nil) }
return CommandChatInputContextPanelTransition(deletions: deletions, insertions: insertions, updates: updates)
}
@ -101,7 +102,8 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode {
private func prepareTransition(from: [CommandChatInputContextPanelEntry]? , to: [CommandChatInputContextPanelEntry]) {
let firstTime = self.currentEntries == nil
let transition = preparedTransition(from: from ?? [], to: to, context: self.context, fontSize: self.fontSize, commandSelected: { [weak self] command, sendImmediately in
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let transition = preparedTransition(from: from ?? [], to: to, context: self.context, presentationData: presentationData, commandSelected: { [weak self] command, sendImmediately in
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
if sendImmediately {
interfaceInteraction.sendBotCommand(command.peer, "/" + command.command.text)

View File

@ -9,20 +9,19 @@ import TelegramPresentationData
import TelegramUIPreferences
import AvatarNode
import AccountContext
import ItemListUI
final class CommandChatInputPanelItem: ListViewItem {
fileprivate let context: AccountContext
fileprivate let theme: PresentationTheme
fileprivate let fontSize: PresentationFontSize
fileprivate let presentationData: ItemListPresentationData
fileprivate let command: PeerCommand
fileprivate let commandSelected: (PeerCommand, Bool) -> Void
let selectable: Bool = true
public init(context: AccountContext, theme: PresentationTheme, fontSize: PresentationFontSize, command: PeerCommand, commandSelected: @escaping (PeerCommand, Bool) -> Void) {
public init(context: AccountContext, presentationData: ItemListPresentationData, command: PeerCommand, commandSelected: @escaping (PeerCommand, Bool) -> Void) {
self.context = context
self.theme = theme
self.fontSize = fontSize
self.presentationData = presentationData
self.command = command
self.commandSelected = commandSelected
}
@ -92,6 +91,8 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
private let highlightedBackgroundNode: ASDisplayNode
private let arrowNode: ASButtonNode
private let activateAreaNode: AccessibilityAreaNode
init() {
self.avatarNode = AvatarNode(font: avatarFont)
self.textNode = TextNode()
@ -107,6 +108,9 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
self.arrowNode = HighlightableButtonNode()
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.button]
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.topSeparatorNode)
@ -117,6 +121,8 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
self.addSubnode(self.arrowNode)
self.arrowNode.addTarget(self, action: #selector(self.arrowButtonPressed), forControlEvents: [.touchUpInside])
self.addSubnode(self.activateAreaNode)
}
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
@ -134,37 +140,40 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
let makeTextLayout = TextNode.asyncLayout(self.textNode)
return { [weak self] item, params, mergedTop, mergedBottom in
let textFont = Font.medium(floor(item.fontSize.baseDisplaySize * 14.0 / 17.0))
let descriptionFont = Font.regular(floor(item.fontSize.baseDisplaySize * 14.0 / 17.0))
let textFont = Font.medium(floor(item.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0))
let descriptionFont = Font.regular(floor(item.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0))
let leftInset: CGFloat = 55.0 + params.leftInset
let rightInset: CGFloat = 10.0 + params.rightInset
let peerName = EnginePeer(item.command.peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
let commandString = NSMutableAttributedString()
commandString.append(NSAttributedString(string: "/" + item.command.command.text, font: textFont, textColor: item.theme.list.itemPrimaryTextColor))
commandString.append(NSAttributedString(string: "/" + item.command.command.text, font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor))
let command = commandString.string
if !item.command.command.description.isEmpty {
commandString.append(NSAttributedString(string: " " + item.command.command.description, font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor))
commandString.append(NSAttributedString(string: " " + item.command.command.description, font: descriptionFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor))
}
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: commandString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - 40.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: HashtagChatInputPanelItemNode.itemHeight), insets: UIEdgeInsets())
let iconImage = PresentationResourcesChat.chatCommandPanelArrowImage(item.theme)
let iconImage = PresentationResourcesChat.chatCommandPanelArrowImage(item.presentationData.theme)
return (nodeLayout, { _ in
if let strongSelf = self {
strongSelf.item = item
strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor
strongSelf.backgroundColor = item.theme.list.plainBackgroundColor
strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor
strongSelf.separatorNode.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor
strongSelf.topSeparatorNode.backgroundColor = item.presentationData.theme.list.itemPlainSeparatorColor
strongSelf.backgroundColor = item.presentationData.theme.list.plainBackgroundColor
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.list.itemHighlightedBackgroundColor
strongSelf.arrowNode.setImage(iconImage, for: [])
strongSelf.avatarNode.setPeer(context: item.context, theme: item.theme, peer: EnginePeer(item.command.peer), emptyColor: item.theme.list.mediaPlaceholderColor)
strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: EnginePeer(item.command.peer), emptyColor: item.presentationData.theme.list.mediaPlaceholderColor)
let _ = textApply()
@ -181,6 +190,10 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: leftInset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset, height: UIScreenPixel))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
strongSelf.activateAreaNode.accessibilityLabel = "\(peerName), \(command)"
strongSelf.activateAreaNode.accessibilityValue = item.command.command.description
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: nodeLayout.size)
}
})
}

View File

@ -72,6 +72,7 @@ final class CommandMenuChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.clipsToBounds = false
self.listView.isOpaque = false
self.listView.stackFromBottom = true
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
@ -234,7 +235,7 @@ final class CommandMenuChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.keepBottomItemOverscrollBackground = self.theme.list.plainBackgroundColor
let new = self.currentEntries?.map({$0.withUpdatedTheme(interfaceState.theme)}) ?? []
prepareTransition(from: self.currentEntries, to: new)
self.prepareTransition(from: self.currentEntries, to: new)
}
}

View File

@ -118,6 +118,8 @@ final class CommandMenuChatInputPanelItemNode: ListViewItemNode {
private let backgroundNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
private let activateAreaNode: AccessibilityAreaNode
init() {
self.textNode = TextNode()
self.commandNode = TextNode()
@ -139,6 +141,9 @@ final class CommandMenuChatInputPanelItemNode: ListViewItemNode {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.clipsToBounds = true
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.button]
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.clippingNode)
@ -148,6 +153,8 @@ final class CommandMenuChatInputPanelItemNode: ListViewItemNode {
self.backgroundNode.addSubnode(self.textNode)
self.backgroundNode.addSubnode(self.commandNode)
self.backgroundNode.addSubnode(self.separatorNode)
self.addSubnode(self.activateAreaNode)
}
override func didLoad() {
@ -227,6 +234,10 @@ final class CommandMenuChatInputPanelItemNode: ListViewItemNode {
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
strongSelf.activateAreaNode.accessibilityLabel = textString.string
strongSelf.activateAreaNode.accessibilityValue = commandString.string
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: nodeLayout.size)
if !mergedTop {
strongSelf.shadowNode.isHidden = false
strongSelf.shadowNode.frame = CGRect(origin: CGPoint(x: -shadowBlur, y: 0.0), size: CGSize(width: nodeLayout.size.width + shadowBlur * 2.0, height: backgroundCornerRadius + shadowBlur))

View File

@ -98,6 +98,8 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
private var recognizer: ItemListRevealOptionsGestureRecognizer?
private var hapticFeedback: HapticFeedback?
private let activateAreaNode: AccessibilityAreaNode
private var item: HashtagChatInputPanelItem?
private var validLayout: (CGSize, CGFloat, CGFloat)?
@ -114,11 +116,16 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.button]
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.topSeparatorNode)
self.addSubnode(self.separatorNode)
self.addSubnode(self.textNode)
self.addSubnode(self.activateAreaNode)
}
override func didLoad() {
@ -150,7 +157,8 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
let leftInset: CGFloat = 15.0 + params.leftInset
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "#\(item.text)", font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: baseWidth, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let title = "#\(item.text)"
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: baseWidth, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let nodeLayout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: HashtagChatInputPanelItemNode.itemHeight), insets: UIEdgeInsets())
@ -177,6 +185,9 @@ final class HashtagChatInputPanelItemNode: ListViewItemNode {
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
strongSelf.activateAreaNode.accessibilityLabel = title
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: nodeLayout.size)
strongSelf.setRevealOptions([ItemListRevealOption(key: 0, title: item.presentationData.strings.Common_Delete, icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)])
strongSelf.setRevealOptionsOpened(item.revealed, animated: animation.isAnimated)
}

View File

@ -108,6 +108,8 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
private var recognizer: ItemListRevealOptionsGestureRecognizer?
private var hapticFeedback: HapticFeedback?
private let activateAreaNode: AccessibilityAreaNode
private var item: MentionChatInputPanelItem?
private var validLayout: (CGSize, CGFloat, CGFloat)?
@ -125,6 +127,9 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.button]
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.topSeparatorNode)
@ -132,6 +137,8 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
self.addSubnode(self.avatarNode)
self.addSubnode(self.textNode)
self.addSubnode(self.activateAreaNode)
}
override func didLoad() {
@ -171,10 +178,14 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
updatedInverted = item.inverted
}
let title = EnginePeer(item.peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
var username: String?
let string = NSMutableAttributedString()
string.append(NSAttributedString(string: item.peer.debugDisplayTitle, font: primaryFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor))
string.append(NSAttributedString(string: title, font: primaryFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor))
if let addressName = item.peer.addressName, !addressName.isEmpty {
string.append(NSAttributedString(string: " @\(addressName)", font: secondaryFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor))
username = "@\(addressName)"
}
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
@ -215,6 +226,10 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
strongSelf.activateAreaNode.accessibilityLabel = title
strongSelf.activateAreaNode.accessibilityValue = username
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: nodeLayout.size)
if let peer = item.peer as? TelegramUser, let _ = peer.botInfo {
strongSelf.setRevealOptions([ItemListRevealOption(key: 0, title: item.presentationData.strings.Common_Delete, icon: .none, color: item.presentationData.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.presentationData.theme.list.itemDisclosureActions.destructive.foregroundColor)])
strongSelf.setRevealOptionsOpened(item.revealed, animated: animation.isAnimated)

View File

@ -63,6 +63,8 @@ final class MultiScaleTextNode: ASDisplayNode {
for (key, state) in states {
if let node = self.stateNodes[key] {
node.textNode.attributedText = NSAttributedString(string: text, font: state.attributes.font, textColor: state.attributes.color)
node.textNode.isAccessibilityElement = true
node.textNode.accessibilityLabel = text
let nodeSize = node.textNode.updateLayout(state.constrainedSize)
let nodeLayout = MultiScaleTextLayout(size: nodeSize)
if key == mainState {

View File

@ -30,6 +30,7 @@ final class PeerInfoScreenCallListItem: PeerInfoScreenItem {
private final class PeerInfoScreenCallListItemNode: PeerInfoScreenItemNode {
private let selectionNode: PeerInfoScreenSelectableBackgroundNode
private let bottomSeparatorNode: ASDisplayNode
private let maskNode: ASImageNode
private var item: PeerInfoScreenCallListItem?
private var itemNode: ItemListCallListItemNode?
@ -42,6 +43,9 @@ private final class PeerInfoScreenCallListItemNode: PeerInfoScreenItemNode {
self.bottomSeparatorNode = ASDisplayNode()
self.bottomSeparatorNode.isLayerBacked = true
self.maskNode = ASImageNode()
self.maskNode.isUserInteractionEnabled = false
super.init()
bringToFrontForHighlightImpl = { [weak self] in
@ -50,6 +54,7 @@ private final class PeerInfoScreenCallListItemNode: PeerInfoScreenItemNode {
self.addSubnode(self.bottomSeparatorNode)
self.addSubnode(self.selectionNode)
self.addSubnode(self.maskNode)
}
override func update(width: CGFloat, safeInsets: UIEdgeInsets, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, hasCorners: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
@ -106,6 +111,14 @@ private final class PeerInfoScreenCallListItemNode: PeerInfoScreenItemNode {
transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel)))
transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0)
let hasCorners = hasCorners && (topItem == nil || bottomItem == nil)
let hasTopCorners = hasCorners && topItem == nil
let hasBottomCorners = hasCorners && bottomItem == nil
self.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
self.maskNode.frame = CGRect(origin: CGPoint(x: safeInsets.left, y: 0.0), size: CGSize(width: width - safeInsets.left - safeInsets.right, height: height))
self.bottomSeparatorNode.isHidden = hasBottomCorners
return height
}
}

View File

@ -527,7 +527,6 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.activateArea.accessibilityLabel = item.label
self.activateArea.accessibilityValue = item.text
let contentSize = CGSize(width: width, height: height)
self.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: contentSize)

View File

@ -2918,7 +2918,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
TitleNodeStateRegular: MultiScaleTextState(attributes: titleAttributes, constrainedSize: titleConstrainedSize),
TitleNodeStateExpanded: MultiScaleTextState(attributes: smallTitleAttributes, constrainedSize: titleConstrainedSize)
], mainState: TitleNodeStateRegular)
self.titleNode.accessibilityLabel = titleStringText
let subtitleNodeLayout = self.subtitleNode.updateLayout(text: subtitleStringText, states: [
TitleNodeStateRegular: MultiScaleTextState(attributes: subtitleAttributes, constrainedSize: titleConstrainedSize),