1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Add 'Sync with computer' theme option (#4973)

This commit is contained in:
Alex Andreev 2022-03-09 16:08:24 +03:00 committed by GitHub
parent a4954b9f8d
commit dd5dfb393d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 102 additions and 3 deletions

View File

@ -0,0 +1,8 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export const setNativeThemeChannel = "theme:set-native-theme";
export const getNativeThemeChannel = "theme:get-native-theme";

View File

@ -29,6 +29,10 @@ jest.mock("electron", () => ({
on: jest.fn(),
handle: jest.fn(),
},
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
console = new Console(stdout, stderr);

View File

@ -56,6 +56,7 @@ import routerInjectable from "./router/router.injectable";
import shellApiRequestInjectable from "./proxy-functions/shell-api-request/shell-api-request.injectable";
import userStoreInjectable from "../common/user-store/user-store.injectable";
import trayMenuItemsInjectable from "./tray/tray-menu-items.injectable";
import { broadcastNativeThemeOnUpdate } from "./native-theme";
const di = getDi();
@ -109,6 +110,8 @@ di.runSetups().then(() => {
}
}
broadcastNativeThemeOnUpdate();
app.on("second-instance", (event, argv) => {
logger.debug("second-instance message");

View File

@ -24,6 +24,8 @@ import { onLocationChange, handleWindowAction } from "../../ipc/window";
import { openFilePickingDialogChannel } from "../../../common/ipc/dialog";
import { showOpenDialog } from "../../ipc/dialog";
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../common/ipc/window";
import { getNativeColorTheme } from "../../native-theme";
import { getNativeThemeChannel } from "../../../common/ipc/native-theme";
interface Dependencies {
electronMenuItems: IComputedValue<MenuRegistration[]>;
@ -158,4 +160,8 @@ export const initIpcMainHandlers = ({ electronMenuItems, directoryForLensLocalSt
y: 20,
});
});
ipcMainHandle(getNativeThemeChannel, () => {
return getNativeColorTheme();
});
};

18
src/main/native-theme.ts Normal file
View File

@ -0,0 +1,18 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { nativeTheme } from "electron";
import { broadcastMessage } from "../common/ipc";
import { setNativeThemeChannel } from "../common/ipc/native-theme";
export function broadcastNativeThemeOnUpdate() {
nativeTheme.on("updated", () => {
broadcastMessage(setNativeThemeChannel, getNativeColorTheme());
});
}
export function getNativeColorTheme() {
return nativeTheme.shouldUseDarkColors ? "dark" : "light";
}

View File

@ -41,6 +41,10 @@ jest.mock("electron", () => ({
on: jest.fn(),
handle: jest.fn(),
},
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
jest.mock("./hotbar-toggle-menu-item", () => ({

View File

@ -45,7 +45,10 @@ const NonInjectedApplication: React.FC<Dependencies> = ({ appPreferenceItems })
<section id="appearance">
<SubTitle title="Theme" />
<Select
options={themeStore.themeOptions}
options={[
{ label: "Sync with computer", value: "system" },
...themeStore.themeOptions,
]}
value={userStore.colorTheme}
onChange={({ value }) => userStore.colorTheme = value}
themeName="lens"

View File

@ -33,6 +33,10 @@ jest.mock("electron", () => ({
on: jest.fn(),
handle: jest.fn(),
},
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
const initialTabs: DockTab[] = [

View File

@ -36,6 +36,10 @@ jest.mock("electron", () => ({
on: jest.fn(),
handle: jest.fn(),
},
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
function mockLogTabViewModel(tabId: TabId, deps: Partial<LogTabViewModelDependencies>): LogTabViewModel {

View File

@ -26,6 +26,13 @@ const mockHotbars: { [id: string]: any } = {
},
};
jest.mock("electron", () => ({
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
describe("<HotbarRemoveCommand />", () => {
let di: DiContainer;
let render: DiRender;

View File

@ -17,6 +17,12 @@ import rendererExtensionsInjectable from "../../../extensions/renderer-extension
import { computed } from "mobx";
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
jest.mock("electron", () => ({
ipcRenderer: {
on: jest.fn(),
invoke: jest.fn(),
},
}));
describe("<Select />", () => {
let di: DiContainer;

View File

@ -13,6 +13,8 @@ import type { SelectOption } from "./components/select";
import type { MonacoEditorProps } from "./components/monaco-editor";
import { defaultTheme } from "../common/vars";
import { camelCase } from "lodash";
import { ipcRenderer } from "electron";
import { getNativeThemeChannel, setNativeThemeChannel } from "../common/ipc/native-theme";
export type ThemeId = string;
@ -34,6 +36,8 @@ export class ThemeStore extends Singleton {
"lens-light": lensLightThemeJson as Theme,
});
@observable osNativeTheme: "dark" | "light" | undefined;
@computed get activeThemeId(): ThemeId {
return UserStore.getInstance().colorTheme;
}
@ -43,7 +47,7 @@ export class ThemeStore extends Singleton {
}
@computed get activeTheme(): Theme {
return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme);
return this.systemTheme ?? this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme);
}
@computed get terminalColors(): [string, string][] {
@ -72,11 +76,25 @@ export class ThemeStore extends Singleton {
}));
}
@computed get systemTheme() {
if (this.activeThemeId == "system" && this.osNativeTheme) {
return this.themes.get(`lens-${this.osNativeTheme}`);
}
return null;
}
constructor() {
super();
makeObservable(this);
autoBind(this);
this.init();
}
async init() {
await this.setNativeTheme();
this.bindNativeThemeUpdateEvent();
// auto-apply active theme
reaction(() => ({
@ -95,12 +113,26 @@ export class ThemeStore extends Singleton {
});
}
bindNativeThemeUpdateEvent() {
ipcRenderer.on(setNativeThemeChannel, (event, theme: "dark" | "light") => {
this.osNativeTheme = theme;
this.applyTheme(theme);
});
}
async setNativeTheme() {
const theme: "dark" | "light" = await ipcRenderer.invoke(getNativeThemeChannel);
this.osNativeTheme = theme;
}
getThemeById(themeId: ThemeId): Theme {
return this.themes.get(themeId);
}
protected applyTheme(themeId: ThemeId) {
const theme = this.getThemeById(themeId);
const theme = this.systemTheme ?? this.getThemeById(themeId);
const colors = Object.entries({
...theme.colors,
...Object.fromEntries(this.terminalColors),