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

Make adding of new tray icons easier by complying to Open Closed Principle

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-07-01 14:57:14 +03:00
parent 47a919e499
commit 23cbc2a2af
No known key found for this signature in database
GPG Key ID: 8C6CFB2FFFE8F68A
11 changed files with 178 additions and 62 deletions

View File

@ -6,11 +6,11 @@ import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { trayMenuItemInjectionToken } from "../tray/tray-menu-item/tray-menu-item-injection-token";
import discoveredUpdateVersionInjectable from "../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import updateIsBeingDownloadedInjectable from "../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
import { withErrorSuppression } from "../../common/utils/with-error-suppression/with-error-suppression";
import { pipeline } from "@ogre-tools/fp";
import withErrorLoggingInjectable from "../../common/utils/with-error-logging/with-error-logging.injectable";
import quitAndInstallUpdateInjectable from "./quit-and-install-update.injectable";
import updateIsReadyToBeInstalledInjectable from "./update-is-ready-to-be-installed.injectable";
const installApplicationUpdateTrayItemInjectable = getInjectable({
id: "install-update-tray-item",
@ -18,8 +18,8 @@ const installApplicationUpdateTrayItemInjectable = getInjectable({
instantiate: (di) => {
const quitAndInstallUpdate = di.inject(quitAndInstallUpdateInjectable);
const discoveredVersionState = di.inject(discoveredUpdateVersionInjectable);
const downloadingUpdateState = di.inject(updateIsBeingDownloadedInjectable);
const withErrorLoggingFor = di.inject(withErrorLoggingInjectable);
const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable);
return {
id: "install-update",
@ -34,9 +34,7 @@ const installApplicationUpdateTrayItemInjectable = getInjectable({
enabled: computed(() => true),
visible: computed(
() => !!discoveredVersionState.value.get() && !downloadingUpdateState.value.get(),
),
visible: updateIsReadyToBeInstalled,
click: pipeline(
quitAndInstallUpdate,

View File

@ -0,0 +1,28 @@
/**
* 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 getTrayIconPathInjectable from "../../tray/menu-icon/get-tray-icon-path.injectable";
import { trayIconInjectionToken } from "../../tray/menu-icon/tray-icon-injection-token";
import updateIsReadyToBeInstalledInjectable from "../update-is-ready-to-be-installed.injectable";
const updateIsReadyToBeInstalledTrayIconInjectable = getInjectable({
id: "update-is-ready-to-be-installed-tray-icon",
instantiate: (di) => {
const getTrayIconPath = di.inject(getTrayIconPathInjectable);
const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable);
return {
iconPath: getTrayIconPath("update-available"),
priority: 1,
shouldBeShown: computed(() => updateIsReadyToBeInstalled.get()),
};
},
injectionToken: trayIconInjectionToken,
});
export default updateIsReadyToBeInstalledTrayIconInjectable;

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 { computed } from "mobx";
import discoveredUpdateVersionInjectable from "../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import updateIsBeingDownloadedInjectable from "../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable";
const updateIsReadyToBeInstalledInjectable = getInjectable({
id: "update-is-ready-to-be-installed",
instantiate: (di) => {
const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable);
const updateIsBeingDownloaded = di.inject(updateIsBeingDownloadedInjectable);
return computed(
() =>
!!discoveredUpdateVersion.value.get() &&
!updateIsBeingDownloaded.value.get(),
);
},
});
export default updateIsReadyToBeInstalledInjectable;

View File

@ -8,8 +8,8 @@ import packageJsonInjectable from "../../../common/vars/package-json.injectable"
import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable";
import isWindowsInjectable from "../../../common/vars/is-windows.injectable";
import loggerInjectable from "../../../common/logger.injectable";
import trayIconPathsInjectable from "../tray-icon-path.injectable";
import { convertToElectronMenuTemplate } from "../reactive-tray-menu-items/converters";
import trayIconInjectable from "../menu-icon/tray-icon.injectable";
const TRAY_LOG_PREFIX = "[TRAY]";
@ -38,13 +38,13 @@ const electronTrayInjectable = getInjectable({
const showApplicationWindow = di.inject(showApplicationWindowInjectable);
const isWindows = di.inject(isWindowsInjectable);
const logger = di.inject(loggerInjectable);
const trayIconPaths = di.inject(trayIconPathsInjectable);
const trayIcon = di.inject(trayIconInjectable);
let tray: Tray;
return {
start: () => {
tray = new Tray(trayIconPaths.normal);
tray = new Tray(trayIcon.get().iconPath);
tray.setToolTip(packageJson.description);
tray.setIgnoreDoubleClickEvents(true);

View File

@ -0,0 +1,37 @@
/**
* 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 getAbsolutePathInjectable from "../../../common/path/get-absolute-path.injectable";
import staticFilesDirectoryInjectable from "../../../common/vars/static-files-directory.injectable";
import isDevelopmentInjectable from "../../../common/vars/is-development.injectable";
import isMacInjectable from "../../../common/vars/is-mac.injectable";
import { camelCase, flow, upperFirst } from "lodash/fp";
const upperCamelCase = flow(camelCase, upperFirst);
const getTrayIconPathInjectable = getInjectable({
id: "get-tray-icon-path",
instantiate: (di) => {
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable);
const isDevelopment = di.inject(isDevelopmentInjectable);
const isMac = di.inject(isMacInjectable);
const baseIconDirectory = getAbsolutePath(
staticFilesDirectory,
isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras
);
const fileSuffix = isMac ? "Template.png" : ".png";
return (name: string) =>
getAbsolutePath(
baseIconDirectory,
`trayIcon${upperCamelCase(name)}${fileSuffix}`,
);
},
});
export default getTrayIconPathInjectable;

View File

@ -0,0 +1,26 @@
/**
* 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 { trayIconInjectionToken } from "./tray-icon-injection-token";
import getTrayIconPathInjectable from "./get-tray-icon-path.injectable";
const normalTrayIconInjectable = getInjectable({
id: "normal-icon",
instantiate: (di) => {
const getTrayIconPath = di.inject(getTrayIconPathInjectable);
return {
iconPath: getTrayIconPath(""),
priority: 999,
shouldBeShown: computed(() => true),
};
},
injectionToken: trayIconInjectionToken,
});
export default normalTrayIconInjectable;

View File

@ -4,27 +4,22 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { reaction } from "mobx";
import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable";
import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable";
import electronTrayInjectable from "../electron-tray/electron-tray.injectable";
import trayIconPathsInjectable from "../tray-icon-path.injectable";
import trayIconInjectable from "./tray-icon.injectable";
const reactiveTrayMenuIconInjectable = getInjectable({
id: "reactive-tray-menu-icon",
instantiate: (di) => {
const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable);
const trayMenuIcon = di.inject(trayIconInjectable);
const electronTray = di.inject(electronTrayInjectable);
const trayIconPaths = di.inject(trayIconPathsInjectable);
return getStartableStoppable("reactive-tray-menu-icon", () => (
reaction(
() => discoveredUpdateVersion.value.get(),
updateVersion => {
if (updateVersion) {
electronTray.setIconPath(trayIconPaths.updateAvailable);
} else {
electronTray.setIconPath(trayIconPaths.normal);
}
() => trayMenuIcon.get(),
icon => {
electronTray.setIconPath(icon.iconPath);
},
{
fireImmediately: true,

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx";
export interface TrayIcon {
iconPath: string;
priority: number;
shouldBeShown: IComputedValue<boolean>;
}
export const trayIconInjectionToken = getInjectionToken<TrayIcon>({
id: "tray-icon-token",
});

View File

@ -0,0 +1,33 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import { find, sortBy } from "lodash/fp";
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import { trayIconInjectionToken } from "./tray-icon-injection-token";
const trayIconInjectable = getInjectable({
id: "tray-icon",
instantiate: (di) => {
const availableIcons = di.injectMany(trayIconInjectionToken);
return computed(() => {
const mostPrioritizedIcon = pipeline(
availableIcons,
sortBy((icon) => icon.priority),
find((icon) => icon.shouldBeShown.get()),
);
if (!mostPrioritizedIcon) {
throw new Error("There should always be tray icon which is shown.");
}
return mostPrioritizedIcon;
});
},
});
export default trayIconInjectable;

View File

@ -1,37 +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 getAbsolutePathInjectable from "../../common/path/get-absolute-path.injectable";
import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable";
import isDevelopmentInjectable from "../../common/vars/is-development.injectable";
import isMacInjectable from "../../common/vars/is-mac.injectable";
export interface TrayIconPaths {
normal: string;
updateAvailable: string;
}
const trayIconPathsInjectable = getInjectable({
id: "tray-icon-paths",
instantiate: (di): TrayIconPaths => {
const getAbsolutePath = di.inject(getAbsolutePathInjectable);
const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable);
const isDevelopment = di.inject(isDevelopmentInjectable);
const isMac = di.inject(isMacInjectable);
const baseIconDirectory = getAbsolutePath(
staticFilesDirectory,
isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras
);
const fileSuffix = isMac ? "Template.png" : ".png";
return {
normal: getAbsolutePath(baseIconDirectory, `trayIcon${fileSuffix}`),
updateAvailable: getAbsolutePath(baseIconDirectory, `trayIconUpdateAvailable${fileSuffix}`),
};
},
});
export default trayIconPathsInjectable;

View File

@ -43,7 +43,6 @@ import applicationWindowInjectable from "../../../main/start-main-application/le
import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting";
import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting";
import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels";
import trayIconPathsInjectable from "../../../main/tray/tray-icon-path.injectable";
import assert from "assert";
import { openMenu } from "react-select-event";
import userEvent from "@testing-library/user-event";
@ -194,11 +193,7 @@ export const getApplicationBuilder = () => {
const traySetMenuItemsMock = jest.fn<any, [MinimalTrayMenuItem[]]>();
mainDi.override(electronTrayInjectable, () => ({
start: () => {
const iconPaths = mainDi.inject(trayIconPathsInjectable);
trayMenuIconPath = iconPaths.normal;
},
start: () => {},
stop: () => {},
setMenuItems: traySetMenuItemsMock,
setIconPath: (path) => {