1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! What VoiceOver is told, and what it can do.
//!
//! Part of [`crate::view::View`]'s chainable API; Rust allows a type's
//! inherent methods to be split across modules, and 400 of them in one file
//! was a file nobody could find anything in.
use super::{View};
use crate::views;
impl View {
// ── What VoiceOver is told ──
//
// The label says what a control is; everything here says the rest of it —
// what it is for, what it currently reads, where it sits in the reading
// order. VoiceOver has no other source for any of it.
/// `.accessibilityHint(_:)` — what happens if the user activates this.
pub fn a11y_hint(self, hint: &str) -> Self {
Self::new(views::accessibility_hint(&self.handle, hint))
}
/// `.accessibilityValue(_:)` — what the control currently reads as, for one
/// whose value is not its label.
pub fn a11y_value(self, value: &str) -> Self {
Self::new(views::accessibility_value(&self.handle, value, true))
}
/// `.accessibilityIdentifier(_:)` — the name a UI test finds this by, not
/// something VoiceOver speaks.
pub fn a11y_identifier(self, id: &str) -> Self {
Self::new(views::accessibility_identifier(&self.handle, id))
}
/// `.accessibilityAddTraits(_:)`
pub fn a11y_add_traits(self, traits: &[views::AccessibilityTrait]) -> Self {
Self::new(views::accessibility_add_traits(&self.handle, traits))
}
/// `.accessibilityRemoveTraits(_:)`
pub fn a11y_remove_traits(self, traits: &[views::AccessibilityTrait]) -> Self {
Self::new(views::accessibility_remove_traits(&self.handle, traits))
}
/// `.accessibilityHeading(_:)` — which heading level this is, so VoiceOver
/// can navigate by them.
pub fn a11y_heading(self, level: views::HeadingLevel) -> Self {
Self::new(views::accessibility_heading(&self.handle, level))
}
/// `.accessibilitySortPriority(_:)` — higher is read first.
pub fn a11y_sort_priority(self, priority: f64) -> Self {
Self::new(views::accessibility_sort_priority(&self.handle, priority))
}
/// `.accessibilityInputLabels(_:)` — the phrases Voice Control accepts for
/// this, when the visible label is awkward to say.
pub fn a11y_input_labels(self, labels: &[&str]) -> Self {
Self::new(views::accessibility_input_labels(&self.handle, labels, true))
}
/// `.accessibilityRespondsToUserInteraction(_:)`
pub fn a11y_responds_to_interaction(self, responds: bool) -> Self {
Self::new(views::accessibility_responds_to_user_interaction(&self.handle, responds))
}
/// `.accessibilityTextContentType(_:)` — what kind of text this is, which
/// changes how VoiceOver reads it.
pub fn a11y_text_content_type(self, kind: views::TextContentType) -> Self {
Self::new(views::accessibility_text_content_type(&self.handle, kind))
}
// ── What VoiceOver can do ──
//
// The attributes above describe a control; these change what VoiceOver can
// *do* with it, and how it groups what it finds. Both matter to somebody
// who cannot see the screen and neither has any other source.
/// `.accessibilityAction(_:_:)` — an action VoiceOver can perform without a
/// visible control for it.
pub fn a11y_action(self, kind: views::ActionKind, action: impl Fn() + 'static) -> Self {
Self::new(views::accessibility_action(&self.handle, kind, action))
}
/// `.accessibilityActions(category:content:)` — several, as a group.
pub fn a11y_actions(self, category: views::ActionCategory, content: View) -> Self {
Self::new(views::accessibility_actions(&self.handle, category, content.handle()))
}
/// `.accessibilityAdjustableAction(_:)` — what a swipe up or down does,
/// which is how VoiceOver drives a slider or stepper.
pub fn a11y_adjustable_action(self, action: impl Fn(i64) + 'static) -> Self {
Self::new(views::accessibility_adjustable_action(&self.handle, action))
}
/// `.accessibilityScrollAction(_:)`
pub fn a11y_scroll_action(self, action: impl Fn(i64) + 'static) -> Self {
Self::new(views::accessibility_scroll_action(&self.handle, action))
}
/// `.accessibilityZoomAction(_:)`
pub fn a11y_zoom_action(self, action: impl Fn() + 'static) -> Self {
Self::new(views::accessibility_zoom_action(&self.handle, action))
}
/// `.accessibilityElement(children:)` — whether descendants are merged into
/// one element, kept as a container, or dropped.
pub fn a11y_element(self, children: views::AccessibilityChildBehavior) -> Self {
Self::new(views::accessibility_element(&self.handle, children))
}
/// `.accessibilityChildren(children:)` — a different subtree for VoiceOver
/// than the one on screen.
pub fn a11y_children(self, children: View) -> Self {
Self::new(views::accessibility_children(&self.handle, children.handle()))
}
/// `.accessibilityRepresentation(representation:)` — stand in for this view
/// with a description of a standard control.
pub fn a11y_representation(self, representation: View) -> Self {
Self::new(views::accessibility_representation(&self.handle, representation.handle()))
}
/// `.accessibilityLabeledPair(role:id:)` — tie a label to the thing it
/// labels, so they are read together.
pub fn a11y_labeled_pair(
self,
role: views::LabeledPairRole,
id: views::HashableValue<'_>,
) -> Self {
Self::new(views::accessibility_labeled_pair(&self.handle, role, id))
}
/// `.accessibilityLinkedGroup(id:)`
pub fn a11y_linked_group<'h>(self, id: impl views::IntoHashable<'h>) -> Self {
Self::new(views::accessibility_linked_group(&self.handle, id.into_hashable()))
}
/// `.accessibilityCustomContent(_:_:importance:)` — extra detail VoiceOver
/// reads on request rather than always.
pub fn a11y_custom_content(
self,
key_label: &str,
id: &str,
value: &str,
importance: views::CustomContentImportance,
) -> Self {
Self::new(views::accessibility_custom_content(
&self.handle,
key_label,
id,
value,
importance,
))
}
/// `.accessibilityActivationPoint(_:)` — where a VoiceOver double-tap lands,
/// for a control whose centre is not where it should be pressed.
pub fn a11y_activation_point(self, x: f64, y: f64) -> Self {
Self::new(views::accessibility_activation_point(&self.handle, x, y))
}
/// `.accessibilityDragPoint(_:description:)`
pub fn a11y_drag_point(self, x: f64, y: f64, description: &str) -> Self {
Self::new(views::accessibility_drag_point(&self.handle, x, y, description, true))
}
/// `.accessibilityDropPoint(_:description:)`
pub fn a11y_drop_point(self, x: f64, y: f64, description: &str) -> Self {
Self::new(views::accessibility_drop_point(&self.handle, x, y, description, true))
}
/// `.accessibilityDirectTouch(_:options:)` — for a view that handles raw
/// touches itself, like an instrument or a drawing canvas.
pub fn a11y_direct_touch(
self,
enabled: bool,
options: &[views::DirectTouchOption],
) -> Self {
Self::new(views::accessibility_direct_touch(&self.handle, enabled, options))
}
/// `.accessibilityScrollStatus(_:)` — what to announce after a scroll.
pub fn a11y_scroll_status(self, status: &str) -> Self {
Self::new(views::accessibility_scroll_status(&self.handle, status, true))
}
/// `.accessibilityShowsLargeContentViewer()`
pub fn a11y_shows_large_content_viewer(self) -> Self {
Self::new(views::accessibility_shows_large_content_viewer(&self.handle))
}
}