Compare commits

..

4 Commits

10 changed files with 132 additions and 3 deletions

View File

@ -236,6 +236,7 @@ struct ComposeAutocompleteEmojisView: View {
CustomEmojiImageView(emoji: emoji) CustomEmojiImageView(emoji: emoji)
.frame(height: emojiSize) .frame(height: emojiSize)
} }
.accessibilityLabel(emoji.shortcode)
} }
} header: { } header: {
if !section.isEmpty { if !section.isEmpty {
@ -271,6 +272,7 @@ struct ComposeAutocompleteEmojisView: View {
.foregroundColor(Color(UIColor.label)) .foregroundColor(Color(UIColor.label))
} }
} }
.accessibilityLabel(emoji.shortcode)
.frame(height: emojiSize) .frame(height: emojiSize)
} }
.animation(.linear(duration: 0.2), value: emojis) .animation(.linear(duration: 0.2), value: emojis)
@ -293,6 +295,7 @@ struct ComposeAutocompleteEmojisView: View {
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.rotationEffect(expanded ? .zero : .degrees(180)) .rotationEffect(expanded ? .zero : .degrees(180))
} }
.accessibilityLabel(expanded ? "Collapse" : "Expand")
.frame(width: 20, height: 20) .frame(width: 20, height: 20)
} }

View File

@ -42,6 +42,8 @@ class FastAccountSwitcherViewController: UIViewController {
view.isHidden = true view.isHidden = true
view.accessibilityViewIsModal = true
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))) view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))))
accountsStack.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))) accountsStack.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))))
} }
@ -67,10 +69,16 @@ class FastAccountSwitcherViewController: UIViewController {
view.isHidden = false view.isHidden = false
func completion() {
UIAccessibility.post(notification: .screenChanged, argument: accountViews.first)
}
if UIAccessibility.prefersCrossFadeTransitions { if UIAccessibility.prefersCrossFadeTransitions {
view.alpha = 0 view.alpha = 0
UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseInOut, .allowUserInteraction]) { UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseInOut, .allowUserInteraction]) {
self.view.alpha = 1 self.view.alpha = 1
} completion: { _ in
completion()
} }
} else { } else {
let totalDuration: TimeInterval = 0.5 let totalDuration: TimeInterval = 0.5
@ -95,6 +103,8 @@ class FastAccountSwitcherViewController: UIViewController {
accountView.transform = .identity accountView.transform = .identity
} }
} }
} completion: { _ in
completion()
} }
} }
} }
@ -114,6 +124,8 @@ class FastAccountSwitcherViewController: UIViewController {
self.view.isHidden = true self.view.isHidden = true
completion?() completion?()
self.view.removeFromSuperview() self.view.removeFromSuperview()
UIAccessibility.post(notification: .screenChanged, argument: nil)
} }
} }
@ -272,6 +284,14 @@ class FastAccountSwitcherViewController: UIViewController {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
} }
override func accessibilityPerformEscape() -> Bool {
guard !view.isHidden else {
return false
}
hide()
return true
}
} }
extension FastAccountSwitcherViewController { extension FastAccountSwitcherViewController {

View File

@ -117,6 +117,8 @@ class FastSwitchingAccountView: UIView {
} }
updateLabelColors() updateLabelColors()
isAccessibilityElement = true
} }
private func setupAccount(account: LocalData.UserAccountInfo) { private func setupAccount(account: LocalData.UserAccountInfo) {
@ -134,12 +136,16 @@ class FastSwitchingAccountView: UIView {
} }
} }
} }
accessibilityLabel = "\(account.username!)@\(account.instanceURL.host!)"
} }
private func setupPlaceholder() { private func setupPlaceholder() {
usernameLabel.text = "Add Account" usernameLabel.text = "Add Account"
instanceLabel.isHidden = true instanceLabel.isHidden = true
avatarImageView.image = UIImage(systemName: "plus") avatarImageView.image = UIImage(systemName: "plus")
accessibilityLabel = "Add Account"
} }
private func updateLabelColors() { private func updateLabelColors() {

View File

@ -296,6 +296,7 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController<
completion(true) completion(true)
} }
} }
dismissAction.accessibilityLabel = "Dismiss Notification"
dismissAction.image = UIImage(systemName: "clear.fill") dismissAction.image = UIImage(systemName: "clear.fill")
let cellConfiguration = (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.trailingSwipeActionsConfiguration() let cellConfiguration = (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.trailingSwipeActionsConfiguration()

View File

@ -222,6 +222,31 @@ class ActionNotificationGroupTableViewCell: UITableViewCell {
updateTimestampWorkItem = nil updateTimestampWorkItem = nil
} }
// MARK: Accessibility
override var accessibilityLabel: String? {
get {
let first = group.notifications.first!
var str = ""
switch group.kind {
case .favourite:
str += "Favorited by "
case .reblog:
str += "Reblogged by "
default:
return nil
}
str += first.account.displayNameWithoutCustomEmoji
if group.notifications.count > 1 {
str += " and \(group.notifications.count - 1) more"
}
str += ", \(first.createdAt.formatted(.relative(presentation: .numeric))), "
str += statusContentLabel.text ?? ""
return str
}
set {}
}
} }
extension ActionNotificationGroupTableViewCell: SelectableTableViewCell { extension ActionNotificationGroupTableViewCell: SelectableTableViewCell {

View File

@ -186,6 +186,22 @@ class FollowNotificationGroupTableViewCell: UITableViewCell {
updateTimestampWorkItem = nil updateTimestampWorkItem = nil
} }
// MARK: Accessibility
override var accessibilityLabel: String? {
get {
let first = group.notifications.first!
var str = "Followed by "
str += first.account.displayNameWithoutCustomEmoji
if group.notifications.count > 1 {
str += " and \(group.notifications.count - 1) more"
}
str += ", \(first.createdAt.formatted(.relative(presentation: .numeric)))"
return str
}
set {}
}
} }
extension FollowNotificationGroupTableViewCell: SelectableTableViewCell { extension FollowNotificationGroupTableViewCell: SelectableTableViewCell {

View File

@ -135,6 +135,29 @@ class FollowRequestNotificationTableViewCell: UITableViewCell {
self.stackView.addArrangedSubview(label) self.stackView.addArrangedSubview(label)
} }
// MARK: Accessibility
override var accessibilityLabel: String? {
get {
guard let notification else { return nil }
var str = "Follow requested by "
str += notification.account.displayNameWithoutCustomEmoji
str += ", \(notification.createdAt.formatted(.relative(presentation: .numeric)))"
return str
}
set {}
}
override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
get {
return [
UIAccessibilityCustomAction(name: "Accept Request", target: self, selector: #selector(acceptButtonPressed)),
UIAccessibilityCustomAction(name: "Reject Request", target: self, selector: #selector(acceptButtonPressed)),
]
}
set {}
}
// MARK: - Interaction // MARK: - Interaction
@IBAction func rejectButtonPressed() { @IBAction func rejectButtonPressed() {

View File

@ -55,7 +55,7 @@
<rect key="frame" x="0.0" y="0.0" width="115" height="26.5"/> <rect key="frame" x="0.0" y="0.0" width="115" height="26.5"/>
<accessibility key="accessibilityConfiguration" label="Accept Request"/> <accessibility key="accessibilityConfiguration" label="Accept Request"/>
<state key="normal" title=" Accept" image="checkmark.circle.fill" catalog="system"> <state key="normal" title=" Accept" image="checkmark.circle.fill" catalog="system">
<color key="titleColor" systemColor="systemBlueColor"/> <color key="titleColor" systemColor="tintColor"/>
</state> </state>
<connections> <connections>
<action selector="acceptButtonPressed" destination="Pcu-ap-Xqf" eventType="touchUpInside" id="hGw-3d-RNi"/> <action selector="acceptButtonPressed" destination="Pcu-ap-Xqf" eventType="touchUpInside" id="hGw-3d-RNi"/>
@ -64,7 +64,7 @@
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" pointerInteraction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7MW-rY-m5l"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" pointerInteraction="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7MW-rY-m5l">
<rect key="frame" x="115" y="0.0" width="115" height="26.5"/> <rect key="frame" x="115" y="0.0" width="115" height="26.5"/>
<state key="normal" title=" Reject" image="xmark.circle.fill" catalog="system"> <state key="normal" title=" Reject" image="xmark.circle.fill" catalog="system">
<color key="titleColor" systemColor="systemBlueColor"/> <color key="titleColor" systemColor="tintColor"/>
</state> </state>
<connections> <connections>
<action selector="rejectButtonPressed" destination="Pcu-ap-Xqf" eventType="touchUpInside" id="EP6-Bg-3nC"/> <action selector="rejectButtonPressed" destination="Pcu-ap-Xqf" eventType="touchUpInside" id="EP6-Bg-3nC"/>
@ -111,7 +111,7 @@
<systemColor name="secondaryLabelColor"> <systemColor name="secondaryLabelColor">
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/> <color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor> </systemColor>
<systemColor name="systemBlueColor"> <systemColor name="tintColor">
<color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color red="0.0" green="0.47843137254901963" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor> </systemColor>
</resources> </resources>

View File

@ -93,6 +93,25 @@ class PollFinishedTableViewCell: UITableViewCell {
updateTimestampWorkItem = nil updateTimestampWorkItem = nil
} }
// MARK: Accessibility
override var accessibilityLabel: String? {
get {
guard let notification else { return nil }
var str = "Poll from "
str += notification.account.displayNameWithoutCustomEmoji
str += " finished "
str += notification.createdAt.formatted(.relative(presentation: .numeric))
if let poll = notification.status?.poll,
poll.options.contains(where: { ($0.votesCount ?? 0) > 0 }) {
let winner = poll.options.max(by: { ($0.votesCount ?? 0) < ($1.votesCount ?? 0) })!
str += ", winning option: \(winner.title)"
}
return str
}
set {}
}
} }
extension PollFinishedTableViewCell: SelectableTableViewCell { extension PollFinishedTableViewCell: SelectableTableViewCell {

View File

@ -85,6 +85,22 @@ class StatusUpdatedNotificationTableViewCell: UITableViewCell {
updateTimestampWorkItem = nil updateTimestampWorkItem = nil
} }
// MARK: Accessibility
override var accessibilityLabel: String? {
get {
guard let notification else { return nil }
var str = "Post from "
str += notification.account.displayNameWithoutCustomEmoji
str += " edited "
str += notification.createdAt.formatted(.relative(presentation: .numeric))
str += ", "
str += contentLabel.text ?? ""
return str
}
set {}
}
} }
extension StatusUpdatedNotificationTableViewCell: SelectableTableViewCell { extension StatusUpdatedNotificationTableViewCell: SelectableTableViewCell {