Skip to content

Commit

Permalink
Merge pull request #1780 from microsoft/corinagum/1713
Browse files Browse the repository at this point in the history
#1713 Switch High Contrast based off System Preferences
  • Loading branch information
corinagum authored Aug 27, 2019
2 parents b58d796 + 3f91d28 commit 7997c47
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [client] Fixed various accessibility issues in PRs:
- [1775](https://github.com/microsoft/BotFramework-Emulator/pull/1775)
- [1776](https://github.com/microsoft/BotFramework-Emulator/pull/1776)
- [1780](https://github.com/microsoft/BotFramework-Emulator/pull/1780)
- [1781](https://github.com/microsoft/BotFramework-Emulator/pull/1781)
- [1782](https://github.com/microsoft/BotFramework-Emulator/pull/1782)

Expand Down
4 changes: 4 additions & 0 deletions packages/app/main/src/appMenuBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ jest.mock('electron', () => ({
this.click = options.click;
}
},
systemPreferences: {
isInvertedColorScheme: jest.fn(() => true),
on: jest.fn(() => null),
},
}));

const mockUpdateStatus = {
Expand Down
4 changes: 4 additions & 0 deletions packages/app/main/src/appUpdater.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ jest.mock('electron', () => ({
},
}
),
systemPreferences: {
isInvertedColorScheme: jest.fn(() => true),
on: jest.fn(() => null),
},
}));

const mockSendNotification = jest.fn().mockResolvedValue(undefined);
Expand Down
133 changes: 133 additions & 0 deletions packages/app/main/src/main.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

import * as path from 'path';

import { CommandServiceImpl, CommandServiceInstance } from '@bfemulator/sdk-shared';
import { SharedConstants } from '@bfemulator/app-shared';
import { systemPreferences } from 'electron';

import { emulatorApplication } from './main';

jest.mock('electron', () => ({
app: {
on: () => void 0,
setName: () => void 0,
},
ipcMain: new Proxy(
{},
{
get(): any {
return () => ({});
},
has() {
return true;
},
}
),
ipcRenderer: new Proxy(
{},
{
get(): any {
return () => ({});
},
has() {
return true;
},
}
),
systemPreferences: {
isInvertedColorScheme: jest.fn(() => true),
on: jest.fn(() => null),
onInvertedColorSchemeChanged: jest.fn(() => true),
},
}));

describe('main', () => {
let commandService: CommandServiceImpl;
let emulatorAppSpy;

beforeEach(() => {
emulatorAppSpy = jest.spyOn(emulatorApplication as any, 'onInvertedColorSchemeChanged');
const decorator = CommandServiceInstance();
const descriptor = decorator({ descriptor: {} }, 'none') as any;
commandService = descriptor.descriptor.get();
});

afterEach(() => {
emulatorAppSpy.mockClear();
});

it('should call `onInvertedColorSchemeChanged` when `inverted-color-scheme-changed` event is triggered', () => {
const onSpy = jest.spyOn(systemPreferences, 'on');

(emulatorApplication as any).initializeSystemPreferencesListeners();

expect(onSpy).toHaveBeenCalledWith('inverted-color-scheme-changed', jasmine.any(Function));

onSpy.mockClear();
});

it('should call command to invert colors `onInvertedColorSchemeChanged`', () => {
const commandServiceSpy = jest.spyOn(commandService, 'remoteCall');

(emulatorApplication as any).onInvertedColorSchemeChanged();

expect(commandServiceSpy).toHaveBeenCalledTimes(1);
expect(commandServiceSpy).toHaveBeenCalledWith(
SharedConstants.Commands.UI.SwitchTheme,
'high-contrast',
path.join('.', 'themes', 'high-contrast.css')
);

commandServiceSpy.mockClear();
});

it('should not change to high contrast when theme is not high contrast', () => {
const commandServiceSpy = jest.spyOn(commandService, 'remoteCall');

(systemPreferences.isInvertedColorScheme as any).mockImplementationOnce(() => false);

(emulatorApplication as any).onInvertedColorSchemeChanged();

expect(commandServiceSpy).toBeCalledTimes(1);

expect(commandServiceSpy).toHaveBeenCalledWith(
SharedConstants.Commands.UI.SwitchTheme,
'Light',
'./themes/light.css'
);

commandServiceSpy.mockClear();
});
});
27 changes: 20 additions & 7 deletions packages/app/main/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { Emulator } from './emulator';
import './fetchProxy';
import { Window } from './platform/window';
import { azureLoggedInUserChanged } from './state/actions/azureAuthActions';
import { rememberBounds, rememberTheme } from './state/actions/windowStateActions';
import { rememberBounds } from './state/actions/windowStateActions';
import { dispatch, getSettings, store } from './state/store';
import { TelemetryService } from './telemetry';
import { botListsAreDifferent, ensureStoragePath, isMac, saveSettings, writeFile } from './utils';
Expand Down Expand Up @@ -139,6 +139,7 @@ class EmulatorApplication {
constructor() {
this.initializeNgrokListeners();
this.initializeAppListeners();
this.initializeSystemPreferencesListeners();
store.subscribe(this.storeSubscriptionHandler);
}

Expand All @@ -155,6 +156,10 @@ class EmulatorApplication {
Emulator.getInstance().ngrok.ngrokEmitter.on('expired', this.onNgrokSessionExpired);
}

private initializeSystemPreferencesListeners() {
systemPreferences.on('inverted-color-scheme-changed', this.onInvertedColorSchemeChanged);
}

private initializeAppListeners() {
app.on('ready', this.onAppReady);
app.on('activate', this.onAppActivate);
Expand All @@ -174,12 +179,8 @@ class EmulatorApplication {
};

private onBrowserWindowReadyToShow = async () => {
const { zoomLevel, theme, availableThemes } = getSettings().windowState;
const themeInfo = availableThemes.find(availableTheme => availableTheme.name === theme);
const isHighContrast = systemPreferences.isInvertedColorScheme();
if (themeInfo) {
store.dispatch(rememberTheme(isHighContrast ? 'high-contrast' : themeInfo.name));
}
this.onInvertedColorSchemeChanged();
const { zoomLevel } = getSettings().windowState;
this.mainWindow.webContents.setZoomLevel(zoomLevel);
SplashScreen.hide();
this.mainBrowserWindow.show();
Expand Down Expand Up @@ -263,6 +264,18 @@ class EmulatorApplication {
Emulator.getInstance().ngrok.broadcastNgrokExpired();
};

private onInvertedColorSchemeChanged = () => {
const { theme, availableThemes } = getSettings().windowState;
const themeInfo = availableThemes.find(availableTheme => availableTheme.name === theme);

const isHighContrast = systemPreferences.isInvertedColorScheme();

const themeName = isHighContrast ? 'high-contrast' : themeInfo.name;
const themeComponents = isHighContrast ? path.join('.', 'themes', 'high-contrast.css') : themeInfo.href;

this.commandService.remoteCall(SharedConstants.Commands.UI.SwitchTheme, themeName, themeComponents);
};

// App listeners
private onAppReady = () => {
if (this.mainBrowserWindow) {
Expand Down

0 comments on commit 7997c47

Please sign in to comment.