• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// TODO(yjbanov): TalkBack on Android incorrectly reads state changes for radio
6//                buttons. When checking a radio button it reads
7//                "Checked, not checked". This is likely due to another radio
8//                button automatically becoming unchecked. VoiceOver reads it
9//                correctly. It is possible we can fix this by using
10//                "radiogroup" and "aria-owns". This may require a change in the
11//                framework. Currently the framework does not report the
12//                grouping of radio buttons.
13
14part of engine;
15
16/// The specific type of checkable control.
17enum _CheckableKind {
18  /// A checkbox. An element, which has [ui.SemanticsFlag.hasCheckedState] set
19  /// and does not have [ui.SemanticsFlag.isInMutuallyExclusiveGroup] or
20  /// [ui.SemanticsFlag.hasToggledState] state, is marked as a checkbox.
21  checkbox,
22
23  /// A radio button, defined by [ui.SemanticsFlag.isInMutuallyExclusiveGroup].
24  radio,
25
26  /// A switch, defined by [ui.SemanticsFlag.hasToggledState].
27  toggle,
28}
29
30/// Renders semantics objects that have checkable (on/off) states.
31///
32/// Three objects which are implemented by this class are checkboxes, radio
33/// buttons and switches.
34///
35/// See also [ui.SemanticsFlag.hasCheckedState], [ui.SemanticsFlag.isChecked],
36/// [ui.SemanticsFlag.isInMutuallyExclusiveGroup], [ui.SemanticsFlag.isToggled],
37/// [ui.SemanticsFlag.hasToggledState]
38class Checkable extends RoleManager {
39  _CheckableKind _kind;
40
41  Checkable(SemanticsObject semanticsObject)
42      : super(Role.checkable, semanticsObject) {
43    if (semanticsObject.hasFlag(ui.SemanticsFlag.isInMutuallyExclusiveGroup)) {
44      _kind = _CheckableKind.radio;
45    } else if (semanticsObject.hasFlag(ui.SemanticsFlag.hasToggledState)) {
46      _kind = _CheckableKind.toggle;
47    } else {
48      _kind = _CheckableKind.checkbox;
49    }
50  }
51
52  @override
53  void update() {
54    if (semanticsObject.isFlagsDirty) {
55      switch (_kind) {
56        case _CheckableKind.checkbox:
57          semanticsObject.setAriaRole('checkbox', true);
58          break;
59        case _CheckableKind.radio:
60          semanticsObject.setAriaRole('radio', true);
61          break;
62        case _CheckableKind.toggle:
63          semanticsObject.setAriaRole('switch', true);
64          break;
65      }
66
67      /// Adding disabled and aria-disabled attribute to notify the assistive
68      /// technologies of disabled elements.
69      _updateDisabledAttribute();
70
71      semanticsObject.element.setAttribute(
72        'aria-checked',
73        (semanticsObject.hasFlag(ui.SemanticsFlag.isChecked) ||
74                semanticsObject.hasFlag(ui.SemanticsFlag.isToggled))
75            ? 'true'
76            : 'false',
77      );
78    }
79  }
80
81  @override
82  void dispose() {
83    switch (_kind) {
84      case _CheckableKind.checkbox:
85        semanticsObject.setAriaRole('checkbox', false);
86        break;
87      case _CheckableKind.radio:
88        semanticsObject.setAriaRole('radio', false);
89        break;
90      case _CheckableKind.toggle:
91        semanticsObject.setAriaRole('switch', false);
92        break;
93    }
94    _removeDisabledAttribute();
95  }
96
97  void _updateDisabledAttribute() {
98    if (!semanticsObject.hasFlag(ui.SemanticsFlag.isEnabled)) {
99      final html.Element element = semanticsObject.element;
100      element
101        ..setAttribute('aria-disabled', 'true')
102        ..setAttribute('disabled', 'true');
103    } else {
104      _removeDisabledAttribute();
105    }
106  }
107
108  void _removeDisabledAttribute() {
109    final html.Element element = semanticsObject.element;
110    element..removeAttribute('aria-disabled')..removeAttribute('disabled');
111  }
112}
113