Skip to content

Commit

Permalink
Add high contrast API to AccessibilityInfo (#742)
Browse files Browse the repository at this point in the history
* Add high contrast API to AccessibilityInfo

* Make RCTAccessibilityManager require main queue setup

* Remove unnecessary removeObserver: call

* Add comment for macOS "high contrast" = "increase contrast"
  • Loading branch information
appden authored Mar 18, 2021
1 parent 3056c4e commit e9e4980
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ const AccessibilityInfo = {
return Promise.resolve(false);
},

/**
* macOS only
*/
isHighContrastEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},

/**
* iOS only
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ const AccessibilityInfo = {
});
},

/**
* macOS only
*/
isHighContrastEnabled: function(): Promise<boolean> {
return Promise.resolve(false);
},

/**
* Query whether inverted colors are currently enabled.
*
Expand Down
18 changes: 18 additions & 0 deletions Libraries/Components/AccessibilityInfo/AccessibilityInfo.macos.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'
import NativeAccessibilityManager from './NativeAccessibilityManager';

const CHANGE_EVENT_NAME = {
highContrastChanged: 'highContrastChanged',
invertColorsChanged: 'invertColorsChanged',
reduceMotionChanged: 'reduceMotionChanged',
reduceTransparencyChanged: 'reduceTransparencyChanged',
Expand All @@ -26,6 +27,7 @@ const CHANGE_EVENT_NAME = {

type ChangeEventName = $Keys<{
change: string,
highContrastChanged: string,
invertColorsChanged: string,
reduceMotionChanged: string,
reduceTransparencyChanged: string,
Expand Down Expand Up @@ -58,6 +60,22 @@ const AccessibilityInfo = {
return Promise.resolve(false);
},

/**
* Query whether high contrast is currently enabled.
*
* Returns a promise which resolves to a boolean.
* The result is `true` when invert color is enabled and `false` otherwise.
*/
isHighContrastEnabled: function(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (NativeAccessibilityManager) {
NativeAccessibilityManager.getCurrentHighContrastState(resolve, reject);
} else {
reject(reject);
}
});
},

/**
* Query whether inverted colors are currently enabled.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export interface Spec extends TurboModule {
onSuccess: (isGrayscaleEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
// [TODO(macOS ISS#2323203)
+getCurrentHighContrastState: (
onSuccess: (isHighContrastEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
// ]TODO(macOS ISS#2323203)
+getCurrentInvertColorsState: (
onSuccess: (isInvertColorsEnabled: boolean) => void,
onError: (error: Object) => void,
Expand Down
26 changes: 26 additions & 0 deletions RNTester/js/examples/Accessibility/AccessibilityExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,16 @@ class DisplayOptionsStatusExample extends React.Component<{}> {
state = {};

componentDidMount() {
AccessibilityInfo.addEventListener(
'highContrastChanged',
this._handleHighContrastToggled,
);
AccessibilityInfo.isHighContrastEnabled().done(isEnabled => {
this.setState({
highContrastEnabled: isEnabled,
});
});

AccessibilityInfo.addEventListener(
'invertColorsChanged',
this._handleInvertColorsToggled,
Expand Down Expand Up @@ -771,6 +781,10 @@ class DisplayOptionsStatusExample extends React.Component<{}> {
}

componentWillUnmount() {
AccessibilityInfo.removeEventListener(
'highContrastChanged',
this._handleHighContrastToggled,
);
AccessibilityInfo.removeEventListener(
'invertColorsChanged',
this._handleInvertColorsToggled,
Expand All @@ -785,6 +799,12 @@ class DisplayOptionsStatusExample extends React.Component<{}> {
);
}

_handleHighContrastToggled = isEnabled => {
this.setState({
highContrastEnabled: isEnabled,
});
};

_handleInvertColorsToggled = isEnabled => {
this.setState({
invertColorsEnabled: isEnabled,
Expand All @@ -806,6 +826,12 @@ class DisplayOptionsStatusExample extends React.Component<{}> {
render() {
return (
<View>
<View>
<Text>
High contrast is{' '}
{this.state.highContrastEnabled ? 'enabled' : 'disabled'}.
</Text>
</View>
<View>
<Text>
Invert colors is{' '}
Expand Down
1 change: 1 addition & 0 deletions React/CoreModules/RCTAccessibilityManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extern NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification; /

@property (nonatomic, assign) BOOL isBoldTextEnabled;
@property (nonatomic, assign) BOOL isGrayscaleEnabled;
@property (nonatomic, assign) BOOL isHighContrastEnabled; // TODO(macOS ISS#2323203) - maps to shouldIncreaseContrast on macOS
@property (nonatomic, assign) BOOL isInvertColorsEnabled;
@property (nonatomic, assign) BOOL isReduceMotionEnabled;
@property (nonatomic, assign) BOOL isReduceTransparencyEnabled;
Expand Down
22 changes: 17 additions & 5 deletions React/Modules/MacOS/RCTAccessibilityManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ @implementation RCTAccessibilityManager

static void *AccessibilityVoiceOverChangeContext = &AccessibilityVoiceOverChangeContext;

+ (BOOL)requiresMainQueueSetup
+ (BOOL)requiresMainQueueSetup
{
return NO;
return YES;
}

- (instancetype)init
- (instancetype)init
{
if (self = [super init]) {
[[NSWorkspace sharedWorkspace] addObserver:self
Expand All @@ -39,11 +39,11 @@ - (instancetype)init
selector:@selector(accessibilityDisplayOptionsChange:)
name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil];
_isHighContrastEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldIncreaseContrast];
_isInvertColorsEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
_isReduceMotionEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
_isReduceTransparencyEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceTransparency];
_isVoiceOverEnabled = [[NSWorkspace sharedWorkspace] isVoiceOverEnabled];

}
return self;
}
Expand All @@ -53,7 +53,6 @@ - (void)dealloc
[[NSWorkspace sharedWorkspace] removeObserver:self
forKeyPath:@"voiceOverEnabled"
context:AccessibilityVoiceOverChangeContext];
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
}

RCT_EXPORT_METHOD(announceForAccessibility:(NSString *)announcement)
Expand All @@ -67,6 +66,12 @@ - (void)dealloc
);
}

RCT_EXPORT_METHOD(getCurrentHighContrastState:(RCTResponseSenderBlock)callback
error:(__unused RCTResponseSenderBlock)error)
{
callback(@[@(_isHighContrastEnabled)]);
}

RCT_EXPORT_METHOD(getCurrentInvertColorsState:(RCTResponseSenderBlock)callback
error:(__unused RCTResponseSenderBlock)error)
{
Expand Down Expand Up @@ -124,9 +129,16 @@ - (void)observeValueForKeyPath:(NSString *)keyPath

- (void)accessibilityDisplayOptionsChange:(NSNotification *)notification
{
BOOL newHighContrastEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldIncreaseContrast];
BOOL newInvertColorsEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldInvertColors];
BOOL newReduceMotionEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
BOOL newReduceTransparencyEnabled = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceTransparency];

if (_isHighContrastEnabled != newHighContrastEnabled) {
_isHighContrastEnabled = newHighContrastEnabled;
[_bridge.eventDispatcher sendDeviceEventWithName:@"highContrastChanged"
body:@(_isHighContrastEnabled)];
}
if (_isInvertColorsEnabled != newInvertColorsEnabled) {
_isInvertColorsEnabled = newInvertColorsEnabled;
[_bridge.eventDispatcher sendDeviceEventWithName:@"invertColorsChanged"
Expand Down

0 comments on commit e9e4980

Please sign in to comment.