diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b26bfe36..e6f4d3c7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Share files generated by webxdc apps directly (#2606) - Tweak menu order (#2604) - Save space by Deduplicating files on sending (#2612) +- Accessibility: voice over reads a reaction summary for messages (#2608) - Fix: Hide read-only chats on forwarding and sort list accordingly (#2436) - Fix: Let 'Cancel' work as expecting when forwarding messages (#2436) - Fix: Preserve filenames on sharing (#2605) diff --git a/deltachat-ios/Chat/Views/Cells/AudioMessageCell.swift b/deltachat-ios/Chat/Views/Cells/AudioMessageCell.swift index 7038bf1c9..a243ce7f0 100644 --- a/deltachat-ios/Chat/Views/Cells/AudioMessageCell.swift +++ b/deltachat-ios/Chat/Views/Cells/AudioMessageCell.swift @@ -50,9 +50,9 @@ public class AudioMessageCell: BaseMessageCell, ReusableCell { mainContentView.spacing = 0 } if msg.type == DC_MSG_VOICE { - accessibilityLabel = String.localized("voice_message") + a11yDcType = String.localized("voice_message") } else { - accessibilityLabel = String.localized("audio") + a11yDcType = String.localized("audio") } delegate?.getAudioDuration(messageId: messageId, successHandler: { [weak self] messageId, duration in diff --git a/deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift b/deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift index b8e5bc492..7931f1e51 100644 --- a/deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift +++ b/deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift @@ -196,6 +196,10 @@ public class BaseMessageCell: UITableViewCell { private var showSelectionBackground: Bool private var timer: Timer? + private var dcContextId: Int? + private var dcMsgId: Int? + var a11yDcType: String? + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { reactionsView = ReactionsView() @@ -517,9 +521,7 @@ public class BaseMessageCell: UITableViewCell { } messageLabel.attributedText = getFormattedText(messageText: msg.text, searchText: searchText, highlight: highlight) - messageLabel.delegate = self - accessibilityLabel = configureAccessibilityString(message: msg) if let reactions = dcContext.getMessageReactions(messageId: msg.id) { reactionsView.isHidden = false @@ -529,6 +531,9 @@ public class BaseMessageCell: UITableViewCell { reactionsView.isHidden = true bottomConstraint?.constant = -3 } + + self.dcContextId = dcContext.id + self.dcMsgId = msg.id } private func getFormattedText(messageText: String?, searchText: String?, highlight: Bool) -> NSAttributedString? { @@ -568,7 +573,13 @@ public class BaseMessageCell: UITableViewCell { return nil } - func configureAccessibilityString(message: DcMsg) -> String { + public override func accessibilityElementDidBecomeFocused() { + logger.info("jit-rendering accessibility string") // jit-rendering is needed as the reactions summary require quite some database calls + guard let dcContextId, let dcMsgId else { return } + let dcContext = DcAccounts.shared.get(id: dcContextId) + let msg = dcContext.getMessage(id: dcMsgId) + let reactions = dcContext.getMessageReactions(messageId: msg.id) + var topLabelAccessibilityString = "" var quoteAccessibilityString = "" var messageLabelAccessibilityString = "" @@ -583,15 +594,24 @@ public class BaseMessageCell: UITableViewCell { if let senderTitle = quoteView.senderTitle.text, let quote = quoteView.quote.text { quoteAccessibilityString = "\(senderTitle), \(quote), \(String.localized("reply_noun")), " } - if let additionalAccessibilityInfo = accessibilityLabel { - additionalAccessibilityString = "\(additionalAccessibilityInfo), " + if let a11yDcType { + additionalAccessibilityString = "\(a11yDcType), " + } + + var reactionsString = "" + if let reactions { + reactionsString = ", " + String.localized(stringID: "n_reactions", parameter: reactions.reactionsByContact.count) + ": " + for (contactId, reactions) in reactions.reactionsByContact { + reactionsString += dcContext.getContact(id: contactId).displayName + ": " + reactions.joined(separator: " ") + ", " + } } - return "\(topLabelAccessibilityString) " + + accessibilityLabel = "\(topLabelAccessibilityString) " + "\(quoteAccessibilityString) " + "\(additionalAccessibilityString) " + "\(messageLabelAccessibilityString) " + - "\(StatusView.getAccessibilityString(message: message))" + "\(StatusView.getAccessibilityString(message: msg))" + + "\(reactionsString) " } func getBackgroundColor(dcContext: DcContext, message: DcMsg) -> UIColor { @@ -637,6 +657,8 @@ public class BaseMessageCell: UITableViewCell { reactionsView.prepareForReuse() timer?.invalidate() timer = nil + dcContextId = nil + dcMsgId = nil } @objc func reactionsViewTapped(_ sender: Any?) { diff --git a/deltachat-ios/Chat/Views/Cells/ContactCardCell.swift b/deltachat-ios/Chat/Views/Cells/ContactCardCell.swift index dde2dfdb8..0350e75b1 100644 --- a/deltachat-ios/Chat/Views/Cells/ContactCardCell.swift +++ b/deltachat-ios/Chat/Views/Cells/ContactCardCell.swift @@ -38,7 +38,7 @@ public class ContactCardCell: BaseMessageCell, ReusableCell { } contactView.configure(message: msg, dcContext: dcContext) - accessibilityLabel = "\(String.localized("document")), \(contactView.configureAccessibilityLabel())" + a11yDcType = "\(String.localized("document")), \(contactView.configureAccessibilityLabel())" super.update(dcContext: dcContext, msg: msg, messageStyle: messageStyle, diff --git a/deltachat-ios/Chat/Views/Cells/FileTextCell.swift b/deltachat-ios/Chat/Views/Cells/FileTextCell.swift index 451aa6ab4..89bbce193 100644 --- a/deltachat-ios/Chat/Views/Cells/FileTextCell.swift +++ b/deltachat-ios/Chat/Views/Cells/FileTextCell.swift @@ -42,7 +42,7 @@ public class FileTextCell: BaseMessageCell, ReusableCell { } fileView.configure(message: msg) - accessibilityLabel = "\(String.localized("document")), \(fileView.configureAccessibilityLabel())" + a11yDcType = "\(String.localized("document")), \(fileView.configureAccessibilityLabel())" super.update(dcContext: dcContext, msg: msg, messageStyle: messageStyle, diff --git a/deltachat-ios/Chat/Views/Cells/ImageTextCell.swift b/deltachat-ios/Chat/Views/Cells/ImageTextCell.swift index 888f45cc1..6373598a0 100644 --- a/deltachat-ios/Chat/Views/Cells/ImageTextCell.swift +++ b/deltachat-ios/Chat/Views/Cells/ImageTextCell.swift @@ -68,11 +68,11 @@ class ImageTextCell: BaseMessageCell, ReusableCell { size: CGSize(width: 500, height: 500))) contentImageIsPlaceholder = false playButtonView.isHidden = true - accessibilityLabel = msg.type == DC_MSG_GIF ? String.localized("gif") : String.localized("image") + a11yDcType = msg.type == DC_MSG_GIF ? String.localized("gif") : String.localized("image") setAspectRatioFor(message: msg) } else if msg.type == DC_MSG_VIDEO, let url = msg.fileURL { playButtonView.isHidden = false - accessibilityLabel = String.localized("video") + a11yDcType = String.localized("video") let placeholderImage = UIImage(color: UIColor.init(alpha: 0, red: 255, green: 255, blue: 255), size: CGSize(width: 250, height: 250)) contentImageView.image = placeholderImage DispatchQueue.global(qos: .userInteractive).async { diff --git a/deltachat-ios/Chat/Views/Cells/WebxdcCell.swift b/deltachat-ios/Chat/Views/Cells/WebxdcCell.swift index dfcf4f964..1435e0566 100644 --- a/deltachat-ios/Chat/Views/Cells/WebxdcCell.swift +++ b/deltachat-ios/Chat/Views/Cells/WebxdcCell.swift @@ -20,6 +20,6 @@ public class WebxdcCell: FileTextCell { showName: showName, searchText: searchText, highlight: highlight) - accessibilityLabel = fileView.configureAccessibilityLabel() + a11yDcType = fileView.configureAccessibilityLabel() } }