Add option for automatic dark theme (#2759)
Summary:
Add an setting option to allow automatic dark theme
A feature requested by swrobel https://github.com/facebook/flipper/issues/2708
## Changelog
### UI change
Replace the `Enable Dark Theme` Toggle button with a Radio group containing three Radio buttons.
The available options are `Dark`, `Light` and `Use System Default`, of which `Use System Default` is the default value
<img width="548" alt="Screenshot 2021-08-31 at 3 32 44 PM" src="https://user-images.githubusercontent.com/410850/131462798-4e74f757-41fc-4a3f-ba28-53d00fc1cf03.png">
### Data structure change
The `darkMode` property of [Settings](c0cd32564a/desktop/app/src/reducers/settings.tsx (L20)) is changed from `boolean` to `string`, the available values are `dark`, `light` and `auto`
Pull Request resolved: https://github.com/facebook/flipper/pull/2759
Test Plan:
### Test 1
- Step: Choose `Dark` in the Settings page and click on `Apply and Restart` button
- Expect: The application is displayed in Dark mode
### Test 2
- Step: Choose `Light` in the Settings page and click on `Apply and Restart` button
- Expect: The application is displayed in Light mode
### Test 3
- Step: Choose `Use System Default` in the Settings page and click on `Apply and Restart` button
- Expect: The application is displayed in System Default mode
Reviewed By: mweststrate
Differential Revision: D30666966
Pulled By: passy
fbshipit-source-id: a63e91f2d0dbff96890e267062cb75bffd0007f4
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cef1468db7
commit
9a4d94c971
@@ -7,8 +7,9 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {Button} from '../ui';
|
||||
import {Button, FlexColumn} from '../ui';
|
||||
import React, {Component, useContext} from 'react';
|
||||
import {Radio} from 'antd';
|
||||
import {updateSettings, Action} from '../reducers/settings';
|
||||
import {
|
||||
Action as LauncherAction,
|
||||
@@ -245,18 +246,23 @@ class SettingsSheet extends Component<Props, State> {
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
<ToggledSection
|
||||
label="Enable dark theme"
|
||||
toggled={darkMode}
|
||||
onChange={(enabled) => {
|
||||
<FlexColumn style={{paddingLeft: 15, paddingBottom: 10}}>
|
||||
Theme Selection
|
||||
<Radio.Group
|
||||
value={darkMode}
|
||||
onChange={(event) => {
|
||||
this.setState((prevState) => ({
|
||||
updatedSettings: {
|
||||
...prevState.updatedSettings,
|
||||
darkMode: enabled,
|
||||
darkMode: event.target.value,
|
||||
},
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
}}>
|
||||
<Radio.Button value="dark">Dark</Radio.Button>
|
||||
<Radio.Button value="light">Light</Radio.Button>
|
||||
<Radio.Button value="system">Use System Setting</Radio.Button>
|
||||
</Radio.Group>
|
||||
</FlexColumn>
|
||||
<ToggledSection
|
||||
label="React Native keyboard shortcuts"
|
||||
toggled={reactNative.shortcuts.enabled}
|
||||
|
||||
@@ -49,7 +49,7 @@ import styled from '@emotion/styled';
|
||||
import {CopyOutlined} from '@ant-design/icons';
|
||||
import {getVersionString} from './utils/versionString';
|
||||
import {PersistGate} from 'redux-persist/integration/react';
|
||||
import {ipcRenderer} from 'electron';
|
||||
import {ipcRenderer, remote} from 'electron';
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') {
|
||||
// By default Node.JS has its internal certificate storage and doesn't use
|
||||
@@ -213,14 +213,26 @@ function init() {
|
||||
sideEffect(
|
||||
store,
|
||||
{name: 'loadTheme', fireImmediately: false, throttleMs: 500},
|
||||
(state) => ({
|
||||
dark: state.settingsState.darkMode,
|
||||
}),
|
||||
(theme) => {
|
||||
(state) => {
|
||||
const theme = state.settingsState.darkMode;
|
||||
let shouldUseDarkMode = remote.nativeTheme.shouldUseDarkColors;
|
||||
if (theme === 'dark') {
|
||||
shouldUseDarkMode = true;
|
||||
} else if (theme === 'light') {
|
||||
shouldUseDarkMode = false;
|
||||
} else if (theme === 'system') {
|
||||
shouldUseDarkMode = remote.nativeTheme.shouldUseDarkColors;
|
||||
}
|
||||
return {
|
||||
shouldUseDarkMode: shouldUseDarkMode,
|
||||
theme: theme,
|
||||
};
|
||||
},
|
||||
(result) => {
|
||||
(
|
||||
document.getElementById('flipper-theme-import') as HTMLLinkElement
|
||||
).href = `themes/${theme.dark ? 'dark' : 'light'}.css`;
|
||||
ipcRenderer.send('setTheme', theme.dark ? 'dark' : 'light');
|
||||
).href = `themes/${result.shouldUseDarkMode ? 'dark' : 'light'}.css`;
|
||||
ipcRenderer.send('setTheme', result.theme);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export type Settings = {
|
||||
openDevMenu: string;
|
||||
};
|
||||
};
|
||||
darkMode: boolean;
|
||||
darkMode: string;
|
||||
showWelcomeAtStartup: boolean;
|
||||
suppressPluginErrors: boolean;
|
||||
};
|
||||
@@ -78,7 +78,7 @@ const initialState: Settings = {
|
||||
openDevMenu: 'Alt+Shift+D',
|
||||
},
|
||||
},
|
||||
darkMode: false,
|
||||
darkMode: 'auto',
|
||||
showWelcomeAtStartup: true,
|
||||
suppressPluginErrors: false,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import {useStore} from './useStore';
|
||||
import {remote} from 'electron';
|
||||
|
||||
/**
|
||||
* This hook returns whether dark mode is currently being used.
|
||||
@@ -15,5 +16,15 @@ import {useStore} from './useStore';
|
||||
* which will provide colors that reflect the theme
|
||||
*/
|
||||
export function useIsDarkMode(): boolean {
|
||||
return useStore((state) => state.settingsState.darkMode);
|
||||
return useStore((state) => {
|
||||
const darkMode = state.settingsState.darkMode;
|
||||
if (darkMode === 'dark') {
|
||||
return true;
|
||||
} else if (darkMode === 'light') {
|
||||
return false;
|
||||
} else if (darkMode === 'system') {
|
||||
return remote.nativeTheme.shouldUseDarkColors;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -109,9 +109,7 @@ if (argv['disable-gpu'] || process.env.FLIPPER_DISABLE_GPU === '1') {
|
||||
}
|
||||
|
||||
process.env.CONFIG = JSON.stringify(config);
|
||||
if (config.darkMode) {
|
||||
nativeTheme.themeSource = 'dark';
|
||||
}
|
||||
nativeTheme.themeSource = config.darkMode || 'light';
|
||||
|
||||
// possible reference to main app window
|
||||
let win: BrowserWindow;
|
||||
@@ -290,7 +288,7 @@ ipcMain.on('getLaunchTime', (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('setTheme', (_e, mode: 'light' | 'dark') => {
|
||||
ipcMain.on('setTheme', (_e, mode: 'light' | 'dark' | 'system') => {
|
||||
nativeTheme.themeSource = mode;
|
||||
});
|
||||
|
||||
@@ -382,7 +380,7 @@ function createWindow() {
|
||||
configPath,
|
||||
JSON.stringify({
|
||||
...config,
|
||||
darkMode: nativeTheme.themeSource === 'dark',
|
||||
darkMode: nativeTheme.themeSource,
|
||||
lastWindowPosition: {
|
||||
x,
|
||||
y,
|
||||
|
||||
@@ -24,7 +24,7 @@ export type Config = {
|
||||
launcherMsg?: string | undefined;
|
||||
updaterEnabled?: boolean;
|
||||
launcherEnabled?: boolean;
|
||||
darkMode?: boolean;
|
||||
darkMode: 'system' | 'light' | 'dark';
|
||||
};
|
||||
|
||||
export default function setup(argv: any) {
|
||||
@@ -38,6 +38,7 @@ export default function setup(argv: any) {
|
||||
let config: Config = {
|
||||
pluginPaths: [],
|
||||
disabledPlugins: [],
|
||||
darkMode: 'light',
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user