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:
parent
47a919e499
commit
23cbc2a2af
@ -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,
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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);
|
||||
|
||||
37
src/main/tray/menu-icon/get-tray-icon-path.injectable.ts
Normal file
37
src/main/tray/menu-icon/get-tray-icon-path.injectable.ts
Normal 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;
|
||||
26
src/main/tray/menu-icon/normal-tray-icon.injectable.ts
Normal file
26
src/main/tray/menu-icon/normal-tray-icon.injectable.ts
Normal 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;
|
||||
@ -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,
|
||||
|
||||
16
src/main/tray/menu-icon/tray-icon-injection-token.ts
Normal file
16
src/main/tray/menu-icon/tray-icon-injection-token.ts
Normal 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",
|
||||
});
|
||||
33
src/main/tray/menu-icon/tray-icon.injectable.ts
Normal file
33
src/main/tray/menu-icon/tray-icon.injectable.ts
Normal 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;
|
||||
@ -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;
|
||||
@ -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) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user