forked from zelo72/mastodon-ios
feat: make status detail accessible
This commit is contained in:
parent
0f3764e3af
commit
ce80409ead
|
@ -156,6 +156,28 @@
|
||||||
<string>%ld reblogs</string>
|
<string>%ld reblogs</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>plural.count.reply</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
<string>%#@reply_count@</string>
|
||||||
|
<key>reply_count</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSStringFormatSpecTypeKey</key>
|
||||||
|
<string>NSStringPluralRuleType</string>
|
||||||
|
<key>NSStringFormatValueTypeKey</key>
|
||||||
|
<string>ld</string>
|
||||||
|
<key>zero</key>
|
||||||
|
<string>0 replies</string>
|
||||||
|
<key>one</key>
|
||||||
|
<string>1 reply</string>
|
||||||
|
<key>few</key>
|
||||||
|
<string>%ld replies</string>
|
||||||
|
<key>many</key>
|
||||||
|
<string>%ld replies</string>
|
||||||
|
<key>other</key>
|
||||||
|
<string>%ld replies</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
<key>plural.count.vote</key>
|
<key>plural.count.vote</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSStringLocalizedFormatKey</key>
|
<key>NSStringLocalizedFormatKey</key>
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
"show_user_profile": "Show user profile",
|
"show_user_profile": "Show user profile",
|
||||||
"content_warning": "Content Warning",
|
"content_warning": "Content Warning",
|
||||||
"media_content_warning": "Tap anywhere to reveal",
|
"media_content_warning": "Tap anywhere to reveal",
|
||||||
|
"tap_to_reveal": "Tap to reveal",
|
||||||
"poll": {
|
"poll": {
|
||||||
"vote": "Vote",
|
"vote": "Vote",
|
||||||
"closed": "Closed"
|
"closed": "Closed"
|
||||||
|
@ -141,7 +142,11 @@
|
||||||
"favorite": "Favorite",
|
"favorite": "Favorite",
|
||||||
"unfavorite": "Unfavorite",
|
"unfavorite": "Unfavorite",
|
||||||
"menu": "Menu",
|
"menu": "Menu",
|
||||||
"hide": "Hide"
|
"hide": "Hide",
|
||||||
|
"show_image": "Show image",
|
||||||
|
"show_gif": "Show GIF",
|
||||||
|
"show_video_player": "Show video player",
|
||||||
|
"tap_then_hold_to_show_menu": "Tap then hold to show menu"
|
||||||
},
|
},
|
||||||
"tag": {
|
"tag": {
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
|
@ -440,6 +445,11 @@
|
||||||
"title": "Unblock Account",
|
"title": "Unblock Account",
|
||||||
"message": "Confirm to unblock %s"
|
"message": "Confirm to unblock %s"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"accessibility": {
|
||||||
|
"show_avatar_image": "Show avatar image",
|
||||||
|
"edit_avatar_image": "Edit avatar image",
|
||||||
|
"show_banner_image": "Show banner image"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"follower": {
|
"follower": {
|
||||||
|
|
|
@ -21,8 +21,11 @@ extension SearchSection {
|
||||||
) -> UICollectionViewDiffableDataSource<SearchSection, SearchItem> {
|
) -> UICollectionViewDiffableDataSource<SearchSection, SearchItem> {
|
||||||
|
|
||||||
let trendCellRegister = UICollectionView.CellRegistration<TrendCollectionViewCell, Mastodon.Entity.Tag> { cell, indexPath, item in
|
let trendCellRegister = UICollectionView.CellRegistration<TrendCollectionViewCell, Mastodon.Entity.Tag> { cell, indexPath, item in
|
||||||
cell.primaryLabel.text = "#" + item.name
|
let primaryLabelText = "#" + item.name
|
||||||
cell.secondaryLabel.text = L10n.Scene.Search.Recommend.HashTag.peopleTalking(item.talkingPeopleCount ?? 0)
|
let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(item.talkingPeopleCount ?? 0)
|
||||||
|
|
||||||
|
cell.primaryLabel.text = primaryLabelText
|
||||||
|
cell.secondaryLabel.text = secondaryLabelText
|
||||||
|
|
||||||
cell.lineChartView.data = (item.history ?? [])
|
cell.lineChartView.data = (item.history ?? [])
|
||||||
.sorted(by: { $0.day < $1.day }) // latest last
|
.sorted(by: { $0.day < $1.day }) // latest last
|
||||||
|
@ -32,6 +35,12 @@ extension SearchSection {
|
||||||
}
|
}
|
||||||
return CGFloat(point)
|
return CGFloat(point)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell.isAccessibilityElement = true
|
||||||
|
cell.accessibilityLabel = [
|
||||||
|
primaryLabelText,
|
||||||
|
secondaryLabelText
|
||||||
|
].joined(separator: ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
let dataSource = UICollectionViewDiffableDataSource<SearchSection, SearchItem>(
|
let dataSource = UICollectionViewDiffableDataSource<SearchSection, SearchItem>(
|
||||||
|
|
|
@ -75,6 +75,7 @@ final class ProfileHeaderView: UIView {
|
||||||
let avatarButton: AvatarButton = {
|
let avatarButton: AvatarButton = {
|
||||||
let button = AvatarButton()
|
let button = AvatarButton()
|
||||||
button.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 0)))
|
button.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 0)))
|
||||||
|
button.accessibilityLabel = "Avatar image" // FIXME: i18n
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -132,3 +132,4 @@ extension TrendCollectionViewCell {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ final class TrendSectionHeaderCollectionReusableView: UICollectionReusableView {
|
||||||
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 22, weight: .bold))
|
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 22, weight: .bold))
|
||||||
label.textColor = Asset.Colors.Label.primary.color
|
label.textColor = Asset.Colors.Label.primary.color
|
||||||
label.text = L10n.Scene.Search.Recommend.HashTag.title
|
label.text = L10n.Scene.Search.Recommend.HashTag.title
|
||||||
|
label.numberOfLines = 0
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ extension StatusThreadRootTableViewCell {
|
||||||
statusView.delegate = self
|
statusView.delegate = self
|
||||||
|
|
||||||
// a11y
|
// a11y
|
||||||
statusView.contentMetaText.textView.isSelectable = true
|
|
||||||
statusView.contentMetaText.textView.isAccessibilityElement = false
|
statusView.contentMetaText.textView.isAccessibilityElement = false
|
||||||
|
statusView.contentMetaText.textView.isSelectable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
|
@ -91,6 +91,54 @@ extension StatusThreadRootTableViewCell {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension StatusThreadRootTableViewCell {
|
||||||
|
|
||||||
|
override var accessibilityElements: [Any]? {
|
||||||
|
get {
|
||||||
|
var elements = [
|
||||||
|
statusView.headerContainerView,
|
||||||
|
statusView.avatarButton,
|
||||||
|
statusView.authorNameLabel,
|
||||||
|
statusView.menuButton,
|
||||||
|
statusView.authorUsernameLabel,
|
||||||
|
statusView.dateLabel,
|
||||||
|
statusView.contentSensitiveeToggleButton,
|
||||||
|
statusView.spoilerOverlayView,
|
||||||
|
statusView.contentMetaText.textView,
|
||||||
|
statusView.mediaGridContainerView,
|
||||||
|
statusView.pollTableView,
|
||||||
|
statusView.pollStatusStackView,
|
||||||
|
statusView.statusVisibilityView,
|
||||||
|
statusView.actionToolbarContainer,
|
||||||
|
statusView.statusMetricView
|
||||||
|
]
|
||||||
|
|
||||||
|
if !statusView.viewModel.isSensitive {
|
||||||
|
elements.removeAll(where: { $0 === statusView.contentSensitiveeToggleButton })
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusView.viewModel.isContentReveal {
|
||||||
|
elements.removeAll(where: { $0 === statusView.spoilerOverlayView })
|
||||||
|
} else {
|
||||||
|
elements.removeAll(where: { $0 === statusView.contentMetaText.textView })
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusView.statusVisibilityView.isHidden {
|
||||||
|
elements.removeAll(where: { $0 === statusView.statusVisibilityView })
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusView.viewModel.pollItems.isEmpty {
|
||||||
|
elements.removeAll(where: { $0 === statusView.pollTableView })
|
||||||
|
elements.removeAll(where: { $0 === statusView.pollStatusStackView })
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
extension StatusThreadRootTableViewCell: AdaptiveContainerMarginTableViewCell {
|
extension StatusThreadRootTableViewCell: AdaptiveContainerMarginTableViewCell {
|
||||||
var containerView: StatusView {
|
var containerView: StatusView {
|
||||||
statusView
|
statusView
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import MastodonLocalization
|
||||||
|
|
||||||
open class AvatarButton: UIControl {
|
open class AvatarButton: UIControl {
|
||||||
|
|
||||||
|
@ -37,6 +38,9 @@ open class AvatarButton: UIControl {
|
||||||
avatarImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
avatarImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||||
avatarImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
avatarImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
|
accessibilityLabel = L10n.Common.Controls.Status.showUserProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func layoutSubviews() {
|
public override func layoutSubviews() {
|
||||||
|
|
|
@ -74,6 +74,13 @@ public final class MediaGridContainerView: UIView {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
_init()
|
_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override var accessibilityElements: [Any]? {
|
||||||
|
get {
|
||||||
|
mediaViews
|
||||||
|
}
|
||||||
|
set { }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,8 @@ extension MediaView {
|
||||||
extension MediaView {
|
extension MediaView {
|
||||||
private func _init() {
|
private func _init() {
|
||||||
// lazy load content later
|
// lazy load content later
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setup(configuration: Configuration) {
|
public func setup(configuration: Configuration) {
|
||||||
|
@ -115,13 +117,18 @@ extension MediaView {
|
||||||
case .image(let info):
|
case .image(let info):
|
||||||
layoutImage()
|
layoutImage()
|
||||||
bindImage(configuration: configuration, info: info)
|
bindImage(configuration: configuration, info: info)
|
||||||
|
accessibilityLabel = "Show image" // TODO: i18n
|
||||||
case .gif(let info):
|
case .gif(let info):
|
||||||
layoutGIF()
|
layoutGIF()
|
||||||
bindGIF(configuration: configuration, info: info)
|
bindGIF(configuration: configuration, info: info)
|
||||||
|
accessibilityLabel = "Show GIF" // TODO: i18n
|
||||||
case .video(let info):
|
case .video(let info):
|
||||||
layoutVideo()
|
layoutVideo()
|
||||||
bindVideo(configuration: configuration, info: info)
|
bindVideo(configuration: configuration, info: info)
|
||||||
|
accessibilityLabel = "Show video player" // TODO: i18n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accessibilityHint = "Tap then hold to show menu" // TODO: i18n
|
||||||
|
|
||||||
layoutBlurhash()
|
layoutBlurhash()
|
||||||
bindBlurhash(configuration: configuration)
|
bindBlurhash(configuration: configuration)
|
||||||
|
|
|
@ -50,6 +50,8 @@ extension PollOptionView {
|
||||||
@Published public var primaryStripProgressViewTintColor: UIColor = Asset.Colors.brandBlue.color
|
@Published public var primaryStripProgressViewTintColor: UIColor = Asset.Colors.brandBlue.color
|
||||||
@Published public var secondaryStripProgressViewTintColor: UIColor = Asset.Colors.brandBlue.color.withAlphaComponent(0.5)
|
@Published public var secondaryStripProgressViewTintColor: UIColor = Asset.Colors.brandBlue.color.withAlphaComponent(0.5)
|
||||||
|
|
||||||
|
@Published public var groupedAccessibilityLabel = ""
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// selectState
|
// selectState
|
||||||
Publishers.CombineLatest3(
|
Publishers.CombineLatest3(
|
||||||
|
@ -136,9 +138,11 @@ extension PollOptionView.ViewModel {
|
||||||
.sink { metaContent in
|
.sink { metaContent in
|
||||||
guard let metaContent = metaContent else {
|
guard let metaContent = metaContent else {
|
||||||
view.optionTextField.text = ""
|
view.optionTextField.text = ""
|
||||||
|
view.optionTextField.accessibilityLabel = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
view.optionTextField.text = metaContent.string
|
view.optionTextField.text = metaContent.string
|
||||||
|
view.optionTextField.accessibilityLabel = metaContent.string
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
// selectState
|
// selectState
|
||||||
|
@ -175,6 +179,21 @@ extension PollOptionView.ViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
bindAccessibility(view: view)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func bindAccessibility(view: PollOptionView) {
|
||||||
|
$selectState
|
||||||
|
.sink { selectState in
|
||||||
|
switch selectState {
|
||||||
|
case .on:
|
||||||
|
view.accessibilityTraits.insert(.selected)
|
||||||
|
default:
|
||||||
|
view.accessibilityTraits.remove(.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,26 @@ extension PollOptionView {
|
||||||
plusCircleImageView.isHidden = true
|
plusCircleImageView.isHidden = true
|
||||||
|
|
||||||
updateCornerRadius()
|
updateCornerRadius()
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
|
}
|
||||||
|
|
||||||
|
public override var accessibilityLabel: String? {
|
||||||
|
get {
|
||||||
|
switch viewModel.voteState {
|
||||||
|
case .reveal:
|
||||||
|
return [
|
||||||
|
optionTextField,
|
||||||
|
optionPercentageLabel
|
||||||
|
]
|
||||||
|
.compactMap { $0.accessibilityLabel }
|
||||||
|
.joined(separator: ", ")
|
||||||
|
|
||||||
|
case .hidden:
|
||||||
|
return optionTextField.accessibilityLabel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func layoutSubviews() {
|
public override func layoutSubviews() {
|
||||||
|
|
|
@ -698,6 +698,9 @@ extension StatusView.ViewModel {
|
||||||
if let spoilerContent = spoilerContent, !spoilerContent.string.isEmpty {
|
if let spoilerContent = spoilerContent, !spoilerContent.string.isEmpty {
|
||||||
strings.append(L10n.Common.Controls.Status.contentWarning)
|
strings.append(L10n.Common.Controls.Status.contentWarning)
|
||||||
strings.append(spoilerContent.string)
|
strings.append(spoilerContent.string)
|
||||||
|
|
||||||
|
// TODO: replace with "Tap to reveal"
|
||||||
|
strings.append(L10n.Common.Controls.Status.mediaContentWarning)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isContentReveal {
|
if isContentReveal {
|
||||||
|
@ -707,6 +710,21 @@ extension StatusView.ViewModel {
|
||||||
return strings.compactMap { $0 }.joined(separator: ", ")
|
return strings.compactMap { $0 }.joined(separator: ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$isContentReveal
|
||||||
|
.map { isContentReveal in
|
||||||
|
isContentReveal ? L10n.Scene.Compose.Accessibility.enableContentWarning : L10n.Scene.Compose.Accessibility.disableContentWarning
|
||||||
|
}
|
||||||
|
.sink { label in
|
||||||
|
statusView.contentSensitiveeToggleButton.accessibilityLabel = label
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
|
contentAccessibilityLabel
|
||||||
|
.sink { contentAccessibilityLabel in
|
||||||
|
statusView.spoilerOverlayView.accessibilityLabel = contentAccessibilityLabel
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
let meidaAccessibilityLabel = $mediaViewConfigurations
|
let meidaAccessibilityLabel = $mediaViewConfigurations
|
||||||
.map { configurations -> String? in
|
.map { configurations -> String? in
|
||||||
let count = configurations.count
|
let count = configurations.count
|
||||||
|
|
|
@ -61,7 +61,7 @@ public final class StatusView: UIView {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// header
|
// header
|
||||||
let headerContainerView = UIView()
|
public let headerContainerView = UIView()
|
||||||
|
|
||||||
// header icon
|
// header icon
|
||||||
let headerIconImageView: UIImageView = {
|
let headerIconImageView: UIImageView = {
|
||||||
|
@ -106,6 +106,7 @@ public final class StatusView: UIView {
|
||||||
button.tintColor = Asset.Colors.Label.secondary.color
|
button.tintColor = Asset.Colors.Label.secondary.color
|
||||||
let image = UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
|
let image = UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 15)))
|
||||||
button.setImage(image, for: .normal)
|
button.setImage(image, for: .normal)
|
||||||
|
button.accessibilityLabel = L10n.Common.Controls.Status.Actions.menu
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -152,7 +153,7 @@ public final class StatusView: UIView {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// content warning
|
// content warning
|
||||||
let spoilerOverlayView = SpoilerOverlayView()
|
public let spoilerOverlayView = SpoilerOverlayView()
|
||||||
|
|
||||||
// media
|
// media
|
||||||
public let mediaContainerView = UIView()
|
public let mediaContainerView = UIView()
|
||||||
|
@ -173,7 +174,7 @@ public final class StatusView: UIView {
|
||||||
public var pollTableViewHeightLayoutConstraint: NSLayoutConstraint!
|
public var pollTableViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||||
public var pollTableViewDiffableDataSource: UITableViewDiffableDataSource<PollSection, PollItem>?
|
public var pollTableViewDiffableDataSource: UITableViewDiffableDataSource<PollSection, PollItem>?
|
||||||
|
|
||||||
let pollStatusStackView = UIStackView()
|
public let pollStatusStackView = UIStackView()
|
||||||
let pollVoteCountLabel: UILabel = {
|
let pollVoteCountLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
|
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
|
||||||
|
@ -186,6 +187,7 @@ public final class StatusView: UIView {
|
||||||
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
|
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
|
||||||
label.textColor = Asset.Colors.Label.secondary.color
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
label.text = " · "
|
label.text = " · "
|
||||||
|
label.isAccessibilityElement = false
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
let pollCountdownLabel: UILabel = {
|
let pollCountdownLabel: UILabel = {
|
||||||
|
@ -542,7 +544,7 @@ extension StatusView.Style {
|
||||||
// pollTableView
|
// pollTableView
|
||||||
statusView.pollContainerView.addArrangedSubview(statusView.pollTableView)
|
statusView.pollContainerView.addArrangedSubview(statusView.pollTableView)
|
||||||
|
|
||||||
// pollStatusStackView
|
// pollStatusStackView: H - [ pollVoteCountLabel | pollCountdownLabel | pollVoteButton ]
|
||||||
statusView.pollStatusStackView.axis = .horizontal
|
statusView.pollStatusStackView.axis = .horizontal
|
||||||
statusView.pollContainerView.addArrangedSubview(statusView.pollStatusStackView)
|
statusView.pollContainerView.addArrangedSubview(statusView.pollStatusStackView)
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ extension ActionToolbarContainer {
|
||||||
replyButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.reply
|
replyButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.reply
|
||||||
reblogButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.reblog // needs update to follow state
|
reblogButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.reblog // needs update to follow state
|
||||||
favoriteButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.favorite // needs update to follow state
|
favoriteButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.favorite // needs update to follow state
|
||||||
shareButton.accessibilityLabel = L10n.Common.Controls.Status.Actions.menu
|
shareButton.accessibilityLabel = L10n.Common.Controls.Actions.share
|
||||||
|
|
||||||
switch style {
|
switch style {
|
||||||
case .inline:
|
case .inline:
|
||||||
|
@ -219,6 +219,7 @@ extension ActionToolbarContainer {
|
||||||
public func configureReply(count: Int, isEnabled: Bool) {
|
public func configureReply(count: Int, isEnabled: Bool) {
|
||||||
let title = ActionToolbarContainer.title(from: count)
|
let title = ActionToolbarContainer.title(from: count)
|
||||||
replyButton.setTitle(title, for: .normal)
|
replyButton.setTitle(title, for: .normal)
|
||||||
|
replyButton.accessibilityLabel = "\(count) reply" // TODO: i18n
|
||||||
}
|
}
|
||||||
|
|
||||||
public func configureReblog(count: Int, isEnabled: Bool, isHighlighted: Bool) {
|
public func configureReblog(count: Int, isEnabled: Bool, isHighlighted: Bool) {
|
||||||
|
@ -230,6 +231,13 @@ extension ActionToolbarContainer {
|
||||||
reblogButton.tintColor = tintColor
|
reblogButton.tintColor = tintColor
|
||||||
reblogButton.setTitleColor(tintColor, for: .normal)
|
reblogButton.setTitleColor(tintColor, for: .normal)
|
||||||
reblogButton.setTitleColor(tintColor, for: .highlighted)
|
reblogButton.setTitleColor(tintColor, for: .highlighted)
|
||||||
|
|
||||||
|
if isHighlighted {
|
||||||
|
reblogButton.accessibilityTraits.insert(.selected)
|
||||||
|
} else {
|
||||||
|
reblogButton.accessibilityTraits.remove(.selected)
|
||||||
|
}
|
||||||
|
reblogButton.accessibilityLabel = L10n.Plural.Count.reblog(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func configureFavorite(count: Int, isEnabled: Bool, isHighlighted: Bool) {
|
public func configureFavorite(count: Int, isEnabled: Bool, isHighlighted: Bool) {
|
||||||
|
@ -242,6 +250,13 @@ extension ActionToolbarContainer {
|
||||||
favoriteButton.tintColor = tintColor
|
favoriteButton.tintColor = tintColor
|
||||||
favoriteButton.setTitleColor(tintColor, for: .normal)
|
favoriteButton.setTitleColor(tintColor, for: .normal)
|
||||||
favoriteButton.setTitleColor(tintColor, for: .highlighted)
|
favoriteButton.setTitleColor(tintColor, for: .highlighted)
|
||||||
|
|
||||||
|
if isHighlighted {
|
||||||
|
favoriteButton.accessibilityTraits.insert(.selected)
|
||||||
|
} else {
|
||||||
|
favoriteButton.accessibilityTraits.remove(.selected)
|
||||||
|
}
|
||||||
|
favoriteButton.accessibilityLabel = L10n.Plural.Count.favorite(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,8 @@ extension SpoilerOverlayView {
|
||||||
bottomPaddingView.setContentCompressionResistancePriority(.defaultLow - 100, for: .vertical)
|
bottomPaddingView.setContentCompressionResistancePriority(.defaultLow - 100, for: .vertical)
|
||||||
|
|
||||||
spoilerMetaLabel.isUserInteractionEnabled = false
|
spoilerMetaLabel.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
isAccessibilityElement = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setComponentHidden(_ isHidden: Bool) {
|
public func setComponentHidden(_ isHidden: Bool) {
|
||||||
|
|
Loading…
Reference in New Issue