[MM-48080] Update tray icon instantly when the settings change (#2376)
* Update wording and update tray icon instantly when the settings change * Add tests * Include new file
This commit is contained in:
parent
4171774aee
commit
e1f5250c0c
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -22,6 +22,7 @@
|
||||||
"FOCALBOARD",
|
"FOCALBOARD",
|
||||||
"gsettings",
|
"gsettings",
|
||||||
"ICONNAME",
|
"ICONNAME",
|
||||||
|
"inputflash",
|
||||||
"loadscreen",
|
"loadscreen",
|
||||||
"mmjstool",
|
"mmjstool",
|
||||||
"NOSERVERS",
|
"NOSERVERS",
|
||||||
|
@ -29,6 +30,7 @@
|
||||||
"officedocument",
|
"officedocument",
|
||||||
"openxmlformats",
|
"openxmlformats",
|
||||||
"presentationml",
|
"presentationml",
|
||||||
|
"showunreadbadge",
|
||||||
"spreadsheetml",
|
"spreadsheetml",
|
||||||
"textbox",
|
"textbox",
|
||||||
"UNCLOSEABLE",
|
"UNCLOSEABLE",
|
||||||
|
|
|
@ -196,9 +196,9 @@
|
||||||
"renderer.components.settingsPage.showUnreadBadge.description": "Regardless of this setting, mentions are always indicated with a red badge and item count on the {taskbar} icon.",
|
"renderer.components.settingsPage.showUnreadBadge.description": "Regardless of this setting, mentions are always indicated with a red badge and item count on the {taskbar} icon.",
|
||||||
"renderer.components.settingsPage.startAppOnLogin": "Start app on login",
|
"renderer.components.settingsPage.startAppOnLogin": "Start app on login",
|
||||||
"renderer.components.settingsPage.startAppOnLogin.description": "If enabled, the app starts automatically when you log in to your machine.",
|
"renderer.components.settingsPage.startAppOnLogin.description": "If enabled, the app starts automatically when you log in to your machine.",
|
||||||
|
"renderer.components.settingsPage.trayIcon.color": "Icon color: ",
|
||||||
"renderer.components.settingsPage.trayIcon.show": "Show icon in the notification area",
|
"renderer.components.settingsPage.trayIcon.show": "Show icon in the notification area",
|
||||||
"renderer.components.settingsPage.trayIcon.show.darwin": "Show {appName} icon in the menu bar",
|
"renderer.components.settingsPage.trayIcon.show.darwin": "Show {appName} icon in the menu bar",
|
||||||
"renderer.components.settingsPage.trayIcon.theme": "Icon theme: ",
|
|
||||||
"renderer.components.settingsPage.trayIcon.theme.dark": "Dark",
|
"renderer.components.settingsPage.trayIcon.theme.dark": "Dark",
|
||||||
"renderer.components.settingsPage.trayIcon.theme.light": "Light",
|
"renderer.components.settingsPage.trayIcon.theme.light": "Light",
|
||||||
"renderer.components.settingsPage.trayIcon.theme.systemDefault": "Use system default",
|
"renderer.components.settingsPage.trayIcon.theme.systemDefault": "Use system default",
|
||||||
|
|
|
@ -41,7 +41,9 @@ jest.mock('main/AutoLauncher', () => ({
|
||||||
jest.mock('main/badge', () => ({
|
jest.mock('main/badge', () => ({
|
||||||
setUnreadBadgeSetting: jest.fn(),
|
setUnreadBadgeSetting: jest.fn(),
|
||||||
}));
|
}));
|
||||||
jest.mock('main/tray/tray', () => ({}));
|
jest.mock('main/tray/tray', () => ({
|
||||||
|
refreshTrayImages: jest.fn(),
|
||||||
|
}));
|
||||||
jest.mock('main/windows/windowManager', () => ({
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
handleUpdateConfig: jest.fn(),
|
handleUpdateConfig: jest.fn(),
|
||||||
sendToRenderer: jest.fn(),
|
sendToRenderer: jest.fn(),
|
||||||
|
|
|
@ -67,6 +67,10 @@ export function handleConfigUpdate(newConfig: CombinedConfig) {
|
||||||
setLoggingLevel(newConfig.logLevel as LogLevel);
|
setLoggingLevel(newConfig.logLevel as LogLevel);
|
||||||
|
|
||||||
handleUpdateMenuEvent();
|
handleUpdateMenuEvent();
|
||||||
|
if (newConfig.trayIconTheme) {
|
||||||
|
refreshTrayImages(newConfig.trayIconTheme);
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.emit(EMIT_CONFIGURATION, true, newConfig);
|
ipcMain.emit(EMIT_CONFIGURATION, true, newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
193
src/main/tray/tray.test.js
Normal file
193
src/main/tray/tray.test.js
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {handleConfigUpdate} from 'main/app/config';
|
||||||
|
|
||||||
|
import AutoLauncher from 'main/AutoLauncher';
|
||||||
|
|
||||||
|
import * as tray from './tray';
|
||||||
|
|
||||||
|
jest.mock('path', () => ({
|
||||||
|
join: (a, b) => b,
|
||||||
|
resolve: (a, b, c) => (c || b),
|
||||||
|
}));
|
||||||
|
jest.mock('electron', () => {
|
||||||
|
class NativeImageMock {
|
||||||
|
image;
|
||||||
|
|
||||||
|
constructor(path) {
|
||||||
|
this.image = path;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFromPath(path) {
|
||||||
|
return new NativeImageMock(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTemplateImage = () => jest.fn();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
app: {
|
||||||
|
getAppPath: () => '/path/to/app',
|
||||||
|
isReady: jest.fn(),
|
||||||
|
setPath: jest.fn(),
|
||||||
|
},
|
||||||
|
ipcMain: {
|
||||||
|
emit: jest.fn(),
|
||||||
|
handle: jest.fn(),
|
||||||
|
on: jest.fn(),
|
||||||
|
},
|
||||||
|
nativeImage: NativeImageMock,
|
||||||
|
nativeTheme: {
|
||||||
|
shouldUseDarkColors: true, // the value doesn't matter
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
jest.mock('main/app/utils', () => ({
|
||||||
|
handleUpdateMenuEvent: jest.fn(),
|
||||||
|
updateSpellCheckerLocales: jest.fn(),
|
||||||
|
updateServerInfos: jest.fn(),
|
||||||
|
setLoggingLevel: jest.fn(),
|
||||||
|
}));
|
||||||
|
jest.mock('main/app/intercom', () => ({
|
||||||
|
handleMainWindowIsShown: jest.fn(),
|
||||||
|
}));
|
||||||
|
jest.mock('main/AutoLauncher', () => ({
|
||||||
|
enable: jest.fn(),
|
||||||
|
disable: jest.fn(),
|
||||||
|
}));
|
||||||
|
jest.mock('main/badge', () => ({
|
||||||
|
setUnreadBadgeSetting: jest.fn(),
|
||||||
|
}));
|
||||||
|
jest.mock('main/windows/windowManager', () => ({
|
||||||
|
handleUpdateConfig: jest.fn(),
|
||||||
|
sendToRenderer: jest.fn(),
|
||||||
|
initializeCurrentServerName: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('main/tray', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
AutoLauncher.enable.mockResolvedValue({});
|
||||||
|
AutoLauncher.disable.mockResolvedValue({});
|
||||||
|
});
|
||||||
|
describe('config changes', () => {
|
||||||
|
let spy;
|
||||||
|
beforeAll(() => {
|
||||||
|
spy = jest.spyOn(tray, 'refreshTrayImages').mockImplementation();
|
||||||
|
});
|
||||||
|
afterAll(() => {
|
||||||
|
spy.mockRestore();
|
||||||
|
});
|
||||||
|
it('should update the tray icon color immediately when the config is updated', () => {
|
||||||
|
handleConfigUpdate({
|
||||||
|
trayIconTheme: 'light',
|
||||||
|
});
|
||||||
|
expect(tray.refreshTrayImages).toHaveBeenCalledWith('light');
|
||||||
|
});
|
||||||
|
it('should update the tray icon color immediately when the config is updated', () => {
|
||||||
|
handleConfigUpdate({
|
||||||
|
trayIconTheme: 'dark',
|
||||||
|
});
|
||||||
|
expect(tray.refreshTrayImages).toHaveBeenCalledWith('dark');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('darwin', () => {
|
||||||
|
const darwinResultAllThemes = {
|
||||||
|
normal: 'osx/menuIcons/MenuIcon16Template.png',
|
||||||
|
unread: 'osx/menuIcons/MenuIconUnread16Template.png',
|
||||||
|
mention: 'osx/menuIcons/MenuIconUnread16Template.png',
|
||||||
|
};
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'darwin',
|
||||||
|
});
|
||||||
|
const result = tray.refreshTrayImages('light');
|
||||||
|
it.each(Object.keys(result))('match "%s"', (a) => {
|
||||||
|
expect(result[a].image).toBe(darwinResultAllThemes[a]);
|
||||||
|
});
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('win32 - light', () => {
|
||||||
|
const theme = 'light';
|
||||||
|
const winResultLight = {
|
||||||
|
normal: `windows/tray_${theme}.ico`,
|
||||||
|
unread: `windows/tray_${theme}_unread.ico`,
|
||||||
|
mention: `windows/tray_${theme}_mention.ico`,
|
||||||
|
};
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'win32',
|
||||||
|
});
|
||||||
|
const result = tray.refreshTrayImages('light');
|
||||||
|
it.each(Object.keys(result))('match "%s"', (a) => {
|
||||||
|
expect(result[a].image).toBe(winResultLight[a]);
|
||||||
|
});
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('win32 - dark', () => {
|
||||||
|
const theme = 'dark';
|
||||||
|
const winResultDark = {
|
||||||
|
normal: `windows/tray_${theme}.ico`,
|
||||||
|
unread: `windows/tray_${theme}_unread.ico`,
|
||||||
|
mention: `windows/tray_${theme}_mention.ico`,
|
||||||
|
};
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'win32',
|
||||||
|
});
|
||||||
|
const result = tray.refreshTrayImages('dark');
|
||||||
|
it.each(Object.keys(result))('match "%s"', (a) => {
|
||||||
|
expect(result[a].image).toBe(winResultDark[a]);
|
||||||
|
});
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('linux - light', () => {
|
||||||
|
const theme = 'light';
|
||||||
|
const linuxResultLight = {
|
||||||
|
normal: `top_bar_${theme}_16.png`,
|
||||||
|
unread: `top_bar_${theme}_unread_16.png`,
|
||||||
|
mention: `top_bar_${theme}_mention_16.png`,
|
||||||
|
};
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'linux',
|
||||||
|
});
|
||||||
|
const result = tray.refreshTrayImages('light');
|
||||||
|
it.each(Object.keys(result))('match "%s"', (a) => {
|
||||||
|
expect(result[a].image).toBe(linuxResultLight[a]);
|
||||||
|
});
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('linux - dark', () => {
|
||||||
|
const theme = 'dark';
|
||||||
|
const linuxResultDark = {
|
||||||
|
normal: `top_bar_${theme}_16.png`,
|
||||||
|
unread: `top_bar_${theme}_unread_16.png`,
|
||||||
|
mention: `top_bar_${theme}_mention_16.png`,
|
||||||
|
};
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'linux',
|
||||||
|
});
|
||||||
|
const result = tray.refreshTrayImages('dark');
|
||||||
|
it.each(Object.keys(result))('match "%s"', (a) => {
|
||||||
|
expect(result[a].image).toBe(linuxResultDark[a]);
|
||||||
|
});
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -74,8 +74,8 @@ export function refreshTrayImages(trayIconTheme: string) {
|
||||||
return trayImages;
|
return trayImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupTray(icontheme: string) {
|
export function setupTray(iconTheme: string) {
|
||||||
refreshTrayImages(icontheme);
|
refreshTrayImages(iconTheme);
|
||||||
trayIcon = new Tray(trayImages.normal);
|
trayIcon = new Tray(trayImages.normal);
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', () => {
|
systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', () => {
|
||||||
|
|
|
@ -633,7 +633,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
options.push(
|
options.push(
|
||||||
<div
|
<div
|
||||||
style={settingsPage.container}
|
style={settingsPage.container}
|
||||||
key='containerInputSpellchekerURL'
|
key='containerInputSpellcheckerURL'
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
disabled={!this.state.useSpellChecker}
|
disabled={!this.state.useSpellChecker}
|
||||||
|
@ -855,8 +855,8 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
style={{marginLeft: '20px'}}
|
style={{marginLeft: '20px'}}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='renderer.components.settingsPage.trayIcon.theme'
|
id='renderer.components.settingsPage.trayIcon.color'
|
||||||
defaultMessage='Icon theme: '
|
defaultMessage='Icon color: '
|
||||||
/>
|
/>
|
||||||
{window.process.platform === 'win32' &&
|
{window.process.platform === 'win32' &&
|
||||||
<>
|
<>
|
||||||
|
|
Loading…
Reference in a new issue