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

Introduce reactive way to get theme from operating system

Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-05-04 12:55:04 +03:00
parent c7dba52cd0
commit 32bc853279
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
12 changed files with 243 additions and 28 deletions

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 { getInjectable } from "@ogre-tools/injectable";
import nativeThemeInjectable from "./native-theme.injectable";
const getElectronThemeInjectable = getInjectable({
id: "get-electron-theme",
instantiate: (di) => {
const nativeTheme = di.inject(nativeThemeInjectable);
return () => nativeTheme.shouldUseDarkColors ? "dark" : "light";
},
});
export default getElectronThemeInjectable;

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { nativeTheme } from "electron";
const nativeThemeInjectable = getInjectable({
id: "native-theme",
instantiate: () => nativeTheme,
causesSideEffects: true,
});
export default nativeThemeInjectable;

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
import currentOperatingSystemThemeStateInjectable from "../../theme/current-operating-system-theme-state.injectable";
import nativeThemeInjectable from "./native-theme.injectable";
import getElectronThemeInjectable from "./get-electron-theme.injectable";
const syncThemeFromOperatingSystemInjectable = getInjectable({
id: "sync-theme-from-operating-system",
instantiate: (di) => {
const currentThemeState = di.inject(currentOperatingSystemThemeStateInjectable);
const nativeTheme = di.inject(nativeThemeInjectable);
const getElectronTheme = di.inject(getElectronThemeInjectable);
return getStartableStoppable("sync-theme-from-operating-system", () => {
const updateThemeState = () => {
const newTheme = getElectronTheme();
currentThemeState.set(newTheme);
};
nativeTheme.on("updated", updateThemeState);
return () => {
nativeTheme.off("updated", updateThemeState);
};
});
},
});
export default syncThemeFromOperatingSystemInjectable;

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { broadcastNativeThemeOnUpdate } from "../../native-theme";
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/when-application-is-loading-injection-token";
const setupOsThemeUpdatesInjectable = getInjectable({
id: "setup-os-theme-updates",
instantiate: () => ({
run: () => {
broadcastNativeThemeOnUpdate();
},
}),
// Todo: remove explicit usage of IPC to get rid of this.
causesSideEffects: true,
injectionToken: whenApplicationIsLoadingInjectionToken,
});
export default setupOsThemeUpdatesInjectable;

View File

@ -47,7 +47,6 @@ import catalogCategoryRegistryInjectable from "../common/catalog/catalog-categor
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable";
import setupRunnablesForAfterRootFrameIsReadyInjectable from "./start-main-application/runnables/setup-runnables-for-after-root-frame-is-ready.injectable";
import setupOsThemeUpdatesInjectable from "./electron-app/runnables/setup-os-theme-updates.injectable";
import setupSentryInjectable from "./start-main-application/runnables/setup-sentry.injectable";
import setupShellInjectable from "./start-main-application/runnables/setup-shell.injectable";
import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable";
@ -79,6 +78,8 @@ import createElectronWindowForInjectable from "./start-main-application/lens-win
import setupRunnablesAfterWindowIsOpenedInjectable from "./electron-app/runnables/setup-runnables-after-window-is-opened.injectable";
import sendToChannelInElectronBrowserWindowInjectable from "./start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
import getElectronThemeInjectable from "./electron-app/features/get-electron-theme.injectable";
import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable";
export const getDiForUnitTesting = (
{ doGeneralOverrides } = { doGeneralOverrides: false },
@ -136,8 +137,8 @@ export const getDiForUnitTesting = (
di.override(registerChannelInjectable, () => () => undefined);
di.override(directoryForBundledBinariesInjectable, () => "some-bin-directory");
di.override(broadcastMessageInjectable, () => {
throw new Error("Tried to broadcast message over IPC without explicit override.");
di.override(broadcastMessageInjectable, () => (channel) => {
throw new Error(`Tried to broadcast message to channel "${channel}" over IPC without explicit override.`);
});
di.override(spawnInjectable, () => () => {
@ -184,7 +185,6 @@ const overrideRunnablesHavingSideEffects = (di: DiContainer) => {
setupIpcMainHandlersInjectable,
setupLensProxyInjectable,
setupRunnablesForAfterRootFrameIsReadyInjectable,
setupOsThemeUpdatesInjectable,
setupSentryInjectable,
setupShellInjectable,
setupSyncingOfWeblinksInjectable,
@ -224,6 +224,8 @@ const overrideElectronFeatures = (di: DiContainer) => {
di.override(showMessagePopupInjectable, () => () => {});
di.override(waitForElectronToBeReadyInjectable, () => () => Promise.resolve());
di.override(ipcMainInjectable, () => ({}));
di.override(getElectronThemeInjectable, () => () => "dark");
di.override(syncThemeFromOperatingSystemInjectable, () => ({ start: () => {}, stop: () => {} }));
di.override(createElectronWindowForInjectable, () => () => async () => ({
show: () => {},

View File

@ -0,0 +1,27 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { reaction } from "mobx";
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
import { setNativeThemeChannel } from "../../../common/ipc/native-theme";
import currentOperatingSystemThemeInjectable from "../current-operating-system-theme.injectable";
import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable";
const broadcastThemeChangeInjectable = getInjectable({
id: "broadcast-theme-change",
instantiate: (di) => {
const currentTheme = di.inject(currentOperatingSystemThemeInjectable);
const broadcastMessage = di.inject(broadcastMessageInjectable);
return getStartableStoppable("broadcast-theme-change", () =>
reaction(() => currentTheme.get(), (theme) => {
broadcastMessage(setNativeThemeChannel, theme);
}),
);
},
});
export default broadcastThemeChangeInjectable;

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/when-application-is-loading-injection-token";
import broadcastThemeChangeInjectable from "./broadcast-theme-change.injectable";
const startBroadcastingThemeChangeInjectable = getInjectable({
id: "start-broadcasting-theme-change",
instantiate: (di) => {
const broadcastThemeChange = di.inject(broadcastThemeChangeInjectable);
return {
run: async () => {
await broadcastThemeChange.start();
},
};
},
injectionToken: whenApplicationIsLoadingInjectionToken,
});
export default startBroadcastingThemeChangeInjectable;

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import broadcastThemeChangeInjectable from "./broadcast-theme-change.injectable";
import { beforeQuitOfBackEndInjectionToken } from "../../start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
const stopBroadcastingThemeChangeInjectable = getInjectable({
id: "stop-broadcasting-theme-change",
instantiate: (di) => {
const broadcastThemeChange = di.inject(broadcastThemeChangeInjectable);
return {
run: async () => {
await broadcastThemeChange.stop();
},
};
},
injectionToken: beforeQuitOfBackEndInjectionToken,
});
export default stopBroadcastingThemeChangeInjectable;

View File

@ -0,0 +1,24 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { observable } from "mobx";
import getElectronThemeInjectable from "../electron-app/features/get-electron-theme.injectable";
export type Theme = "dark" | "light";
const currentOperatingSystemThemeStateInjectable = getInjectable({
id: "current-operating-system-theme-state",
instantiate: (di) => {
const getElectronTheme = di.inject(getElectronThemeInjectable);
const defaultTheme = getElectronTheme();
return observable.box<Theme>(
defaultTheme,
);
},
});
export default currentOperatingSystemThemeStateInjectable;

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import currentOperatingSystemThemeStateInjectable from "./current-operating-system-theme-state.injectable";
const currentOperatingSystemThemeInjectable = getInjectable({
id: "current-operating-system-theme",
instantiate: (di) => {
const currentThemeState = di.inject(currentOperatingSystemThemeStateInjectable);
return computed(() => currentThemeState.get());
},
});
export default currentOperatingSystemThemeInjectable;

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import syncThemeFromOperatingSystemInjectable from "../../electron-app/features/sync-theme-from-operating-system.injectable";
import { whenApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/when-application-is-loading-injection-token";
const startSyncingThemeFromOperatingSystemInjectable = getInjectable({
id: "start-syncing-theme-from-operating-system",
instantiate: (di) => {
const syncTheme = di.inject(syncThemeFromOperatingSystemInjectable);
return {
run: async () => {
await syncTheme.start();
},
};
},
injectionToken: whenApplicationIsLoadingInjectionToken,
});
export default startSyncingThemeFromOperatingSystemInjectable;

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import syncThemeFromOperatingSystemInjectable from "../../electron-app/features/sync-theme-from-operating-system.injectable";
import { beforeQuitOfBackEndInjectionToken } from "../../start-main-application/runnable-tokens/before-quit-of-back-end-injection-token";
const stopSyncingThemeFromOperatingSystemInjectable = getInjectable({
id: "stop-syncing-theme-from-operating-system",
instantiate: (di) => {
const syncTheme = di.inject(syncThemeFromOperatingSystemInjectable);
return {
run: async () => {
await syncTheme.stop();
},
};
},
injectionToken: beforeQuitOfBackEndInjectionToken,
});
export default stopSyncingThemeFromOperatingSystemInjectable;