From 5969daedacfb6dc2974836100e90003a5637692d Mon Sep 17 00:00:00 2001 From: PiEgg Date: Sat, 31 Dec 2022 20:44:19 +0800 Subject: [PATCH] :construction: WIP: add uploader config list menu & rebuild multi-config communication way --- public/i18n/en.yml | 1 + public/i18n/zh-CN.yml | 1 + public/i18n/zh-TW.yml | 1 + src/main/apis/app/system/index.ts | 21 +--- src/main/events/ipcList.ts | 4 +- src/main/events/picgoCoreIPC.ts | 8 +- src/main/events/remotes/menu.ts | 76 +++++++----- src/renderer/utils/mainMixin.ts | 20 +++- src/universal/events/constants.ts | 1 + src/universal/types/enum.ts | 7 ++ src/universal/types/i18n.d.ts | 1 + src/universal/types/types.d.ts | 30 +++++ src/universal/utils/common.ts | 8 ++ src/universal/utils/handleUploaderConfig.ts | 121 ++++++++++++++++++++ 14 files changed, 247 insertions(+), 53 deletions(-) create mode 100644 src/universal/utils/handleUploaderConfig.ts diff --git a/public/i18n/en.yml b/public/i18n/en.yml index 966f034..9f49a08 100644 --- a/public/i18n/en.yml +++ b/public/i18n/en.yml @@ -23,6 +23,7 @@ CONFIG_THING: Config ${c} FIND_NEW_VERSION: Find New Version NO_MORE_NOTICE: No More Notice SHOW_DEVTOOLS: Show Devtools +CURRENT_PICBED: Current Picbed # ---renderer i18n begin--- diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml index 4ac67da..cf8c658 100644 --- a/public/i18n/zh-CN.yml +++ b/public/i18n/zh-CN.yml @@ -23,6 +23,7 @@ CONFIG_THING: 配置${c} FIND_NEW_VERSION: 发现新版本 NO_MORE_NOTICE: 以后不再提醒 SHOW_DEVTOOLS: 打开开发者工具 +CURRENT_PICBED: 当前图床 # ---renderer i18n begin--- diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml index 0a242af..5ebdd64 100644 --- a/public/i18n/zh-TW.yml +++ b/public/i18n/zh-TW.yml @@ -23,6 +23,7 @@ CONFIG_THING: 設定${c} FIND_NEW_VERSION: 發現新版本 NO_MORE_NOTICE: 以後不再提醒 SHOW_DEVTOOLS: 開啟開發者工具 +CURRENT_PICBED: 當前圖床 # ---renderer i18n begin--- diff --git a/src/main/apis/app/system/index.ts b/src/main/apis/app/system/index.ts index 79486d7..037b978 100644 --- a/src/main/apis/app/system/index.ts +++ b/src/main/apis/app/system/index.ts @@ -9,11 +9,9 @@ import { Notification } from 'electron' import uploader from 'apis/app/uploader' -import getPicBeds from '~/main/utils/getPicBeds' import db, { GalleryDB } from '~/main/apis/core/datastore' import windowManager from 'apis/app/window/windowManager' import { IWindowList } from '#/types/enum' -import picgo from '@core/picgo' import pasteTemplate from '~/main/utils/pasteTemplate' import pkg from 'root/package.json' import { ensureFilePath, handleCopyUrl } from '~/main/utils/common' @@ -21,28 +19,13 @@ import { privacyManager } from '~/main/utils/privacyManager' // import { T } from '#/i18n' import { T } from '~/main/i18n' import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion' +import { buildPicBedListMenu } from '~/main/events/remotes/menu' let contextMenu: Menu | null let menu: Menu | null let tray: Tray | null export function createContextMenu () { - const picBeds = getPicBeds() if (process.platform === 'darwin' || process.platform === 'win32') { - const submenu = picBeds.filter(item => item.visible).map(item => { - return { - label: item.name, - type: 'radio', - checked: db.get('picBed.current') === item.type, - click () { - picgo.saveConfig({ - 'picBed.current': item.type, - 'picBed.uploader': item.type - }) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') - } - } - } - }) + const submenu = buildPicBedListMenu() contextMenu = Menu.buildFromTemplate([ { label: T('ABOUT'), diff --git a/src/main/events/ipcList.ts b/src/main/events/ipcList.ts index abf11c2..1aba3a6 100644 --- a/src/main/events/ipcList.ts +++ b/src/main/events/ipcList.ts @@ -36,7 +36,7 @@ import { } from '~/main/apis/app/uploader/apis' import picgoCoreIPC from './picgoCoreIPC' import { handleCopyUrl } from '~/main/utils/common' -import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildUploadPageMenu } from './remotes/menu' +import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildPicBedListMenu } from './remotes/menu' import path from 'path' import { T } from '~/main/i18n' @@ -186,7 +186,7 @@ export default { }) ipcMain.on(SHOW_UPLOAD_PAGE_MENU, () => { const window = windowManager.get(IWindowList.SETTING_WINDOW)! - const menu = buildUploadPageMenu() + const menu = buildPicBedListMenu() menu.popup({ window }) diff --git a/src/main/events/picgoCoreIPC.ts b/src/main/events/picgoCoreIPC.ts index e5518c6..89e23fc 100644 --- a/src/main/events/picgoCoreIPC.ts +++ b/src/main/events/picgoCoreIPC.ts @@ -29,7 +29,8 @@ import { OPEN_WINDOW, GET_LANGUAGE_LIST, SET_CURRENT_LANGUAGE, - GET_CURRENT_LANGUAGE + GET_CURRENT_LANGUAGE, + RPC_ACTIONS } from '#/events/constants' import { GalleryDB } from 'apis/core/datastore' @@ -395,6 +396,10 @@ const handleI18n = () => { }) } +const handleRPCActions = () => { + ipcMain.on(RPC_ACTIONS, (event: IpcMainEvent, action: IRPCActions, ...args: any[], callbackId: string) => {}) +} + export default { listen () { handleGetPluginList() @@ -409,6 +414,7 @@ export default { handleOpenFile() handleOpenWindow() handleI18n() + handleRPCActions() }, // TODO: separate to single file handlePluginUninstall, diff --git a/src/main/events/remotes/menu.ts b/src/main/events/remotes/menu.ts index e2baf6d..bd46698 100644 --- a/src/main/events/remotes/menu.ts +++ b/src/main/events/remotes/menu.ts @@ -13,6 +13,7 @@ import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, SHOW import picgoCoreIPC from '~/main/events/picgoCoreIPC' import { PicGo as PicGoCore } from 'picgo' import { T } from '~/main/i18n' +import { changeCurrentUploader } from '~/universal/utils/handleUploaderConfig' interface GuiMenuItem { label: string @@ -20,24 +21,7 @@ interface GuiMenuItem { } const buildMiniPageMenu = () => { - const picBeds = getPicBeds() - const current = picgo.getConfig('picBed.uploader') - const submenu = picBeds.filter(item => item.visible).map(item => { - return { - label: item.name, - type: 'radio', - checked: current === item.type, - click () { - picgo.saveConfig({ - 'picBed.current': item.type, - 'picBed.uploader': item.type - }) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') - } - } - } - }) + const submenu = buildPicBedListMenu() const template = [ { label: T('OPEN_MAIN_WINDOW'), @@ -128,26 +112,58 @@ const buildMainPageMenu = (win: BrowserWindow) => { return Menu.buildFromTemplate(template) } -const buildUploadPageMenu = () => { +const buildPicBedListMenu = () => { const picBeds = getPicBeds() const currentPicBed = picgo.getConfig('picBed.uploader') - const submenu = picBeds.filter(item => item.visible).map(item => { + const currentPicBedName = picBeds.find(item => item.type === currentPicBed)?.name + const picBedConfigList = picgo.getConfig('uploader') + const currentPicBedMenuItem = [{ + label: `${T('CURRENT_PICBED')} - ${currentPicBedName}`, + enabled: false + }, { + type: 'separator' + }] + let submenu = picBeds.filter(item => item.visible).map(item => { + const configList = picBedConfigList?.[item.type]?.configList + const defaultId = picBedConfigList?.[item.type]?.defaultId + const hasSubmenu = !!configList return { label: item.name, - type: 'radio', - checked: currentPicBed === item.type, - click () { - picgo.saveConfig({ - 'picBed.current': item.type, - 'picBed.uploader': item.type + type: !hasSubmenu ? 'checkbox' : undefined, + checked: !hasSubmenu ? (currentPicBed === item.type) : undefined, + submenu: hasSubmenu + ? configList.map((config) => { + return { + label: config._configName || 'Default', + // if only one config, use checkbox, or radio will checked as default + // see: https://github.com/electron/electron/issues/21292 + type: 'checkbox', + checked: config._id === defaultId && (item.type === currentPicBed), + click: function () { + changeCurrentUploader(item.type, config, config._id) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + } + } + } }) - if (windowManager.has(IWindowList.SETTING_WINDOW)) { - windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + : undefined, + click: !hasSubmenu + ? function () { + picgo.saveConfig({ + 'picBed.current': item.type, + 'picBed.uploader': item.type + }) + if (windowManager.has(IWindowList.SETTING_WINDOW)) { + windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') + } } - } + : undefined } }) // @ts-ignore + submenu = currentPicBedMenuItem.concat(submenu) + // @ts-ignore return Menu.buildFromTemplate(submenu) } @@ -289,6 +305,6 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => { export { buildMiniPageMenu, buildMainPageMenu, - buildUploadPageMenu, + buildPicBedListMenu, buildPluginPageMenu } diff --git a/src/renderer/utils/mainMixin.ts b/src/renderer/utils/mainMixin.ts index 5056999..c548a73 100644 --- a/src/renderer/utils/mainMixin.ts +++ b/src/renderer/utils/mainMixin.ts @@ -1,7 +1,8 @@ import { Component, Vue } from 'vue-property-decorator' import { ipcRenderer, IpcRendererEvent } from 'electron' -import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, FORCE_UPDATE } from '#/events/constants' +import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, FORCE_UPDATE, RPC_ACTIONS } from '#/events/constants' import { uuid } from 'uuidv4' +import { IRPCActionType } from '~/universal/types/enum' @Component export default class extends Vue { created () { @@ -34,6 +35,23 @@ export default class extends Vue { }) } + /** + * trigger RPC action + */ + triggerRPC (action: IRPCActionType, ...args: any[]): Promise { + return new Promise((resolve) => { + const callbackId = uuid() + const callback = (event: IpcRendererEvent, data: T | undefined, returnActionType: IRPCActionType, returnCallbackId: string) => { + if (returnCallbackId === callbackId && returnActionType === action) { + resolve(data) + ipcRenderer.removeListener(RPC_ACTIONS, callback) + } + } + ipcRenderer.on(RPC_ACTIONS, callback) + ipcRenderer.send(RPC_ACTIONS, action, args, callbackId) + }) + } + forceUpdate () { this.$bus.$emit(FORCE_UPDATE) } diff --git a/src/universal/events/constants.ts b/src/universal/events/constants.ts index 7a8d575..27d9f45 100644 --- a/src/universal/events/constants.ts +++ b/src/universal/events/constants.ts @@ -34,6 +34,7 @@ export const SHOW_MAIN_PAGE_DONATION = 'SHOW_MAIN_PAGE_DONATION' export const FORCE_UPDATE = 'FORCE_UPDATE' export const OPEN_WINDOW = 'OPEN_WINDOW' export const GET_PICBEDS = 'GET_PICBEDS' +export const RPC_ACTIONS = 'RPC_ACTIONS' // i18n export const GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE' export const GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST' diff --git a/src/universal/types/enum.ts b/src/universal/types/enum.ts index 6361dda..db8ef16 100644 --- a/src/universal/types/enum.ts +++ b/src/universal/types/enum.ts @@ -46,3 +46,10 @@ export enum IRemoteNoticeTriggerCount { ONCE = 'ONCE', // default ALWAYS = 'ALWAYS' } + +/** + * renderer trigger action from main + */ +export enum IRPCActionType { + GET_PICBED_CONFIG_LIST = 'GET_PICBED_CONFIG_LIST', +} diff --git a/src/universal/types/i18n.d.ts b/src/universal/types/i18n.d.ts index 69261fd..11a1c94 100644 --- a/src/universal/types/i18n.d.ts +++ b/src/universal/types/i18n.d.ts @@ -24,6 +24,7 @@ interface ILocales { FIND_NEW_VERSION: string NO_MORE_NOTICE: string SHOW_DEVTOOLS: string + CURRENT_PICBED: string CHOOSE_YOUR_DEFAULT_PICBED: string UPLOAD_AREA: string GALLERY: string diff --git a/src/universal/types/types.d.ts b/src/universal/types/types.d.ts index 5858f45..7f6e431 100644 --- a/src/universal/types/types.d.ts +++ b/src/universal/types/types.d.ts @@ -159,6 +159,22 @@ interface IPicGoPluginConfig { [propName: string]: any } +interface IPicGoPluginOriginConfig { + name: string + type: string + required: boolean + default?: any + alias?: string + choices?: { + name?: string + value?: any + }[] | (() => { + name?: string + value?: any + }[]) + [propName: string]: any +} + interface IPluginMenuConfig { name: string fullName?: string @@ -389,3 +405,17 @@ interface IRemoteNoticeButton { interface IRemoteNoticeLocalCountStorage { [id: string]: true | number } + +interface IUploaderListItemMetaInfo { + _id: string + _configName: string + _updatedAt: number + _createdAt: number +} + +interface IUploaderConfig { + [picBedType: string]: { + configList: (IStringKeyMap & IUploaderListItemMetaInfo)[] + defaultId: string + } +} diff --git a/src/universal/utils/common.ts b/src/universal/utils/common.ts index ff1e2ff..0bd3d27 100644 --- a/src/universal/utils/common.ts +++ b/src/universal/utils/common.ts @@ -43,3 +43,11 @@ export const enforceNumber = (num: number | string) => { } export const isDev = process.env.NODE_ENV === 'development' + +export const trimValues = (obj: IStringKeyMap) => { + const newObj = {} as IStringKeyMap + Object.keys(obj).forEach(key => { + newObj[key] = typeof obj[key] === 'string' ? obj[key].trim() : obj[key] + }) + return newObj +} diff --git a/src/universal/utils/handleUploaderConfig.ts b/src/universal/utils/handleUploaderConfig.ts new file mode 100644 index 0000000..99debe2 --- /dev/null +++ b/src/universal/utils/handleUploaderConfig.ts @@ -0,0 +1,121 @@ +import { uuid } from 'uuidv4' +import { trimValues } from '#/utils/common' +import picgo from '@core/picgo' + +export const handleConfigWithFunction = (config: IPicGoPluginOriginConfig[]): IPicGoPluginConfig[] => { + for (const i in config) { + if (typeof config[i].default === 'function') { + config[i].default = config[i].default() + } + if (typeof config[i].choices === 'function') { + config[i].choices = (config[i].choices as Function)() + } + } + return config as IPicGoPluginConfig[] +} + +export const completeUploaderMetaConfig = (originData: IStringKeyMap): IStringKeyMap => { + return Object.assign({ + _configName: 'Default' + }, trimValues(originData), { + _id: uuid(), + _createdAt: Date.now(), + _updatedAt: Date.now() + }) +} + +/** + * get picbed config by type + * it will trigger the uploader config function & get the uploader config result + * & not just read from + */ +export const getPicBedConfig = (type: string) => { + const name = picgo.helper.uploader.get(type)?.name || type + if (picgo.helper.uploader.get(type)?.config) { + const _config = picgo.helper.uploader.get(type)!.config!(picgo) + const config = handleConfigWithFunction(_config) + return { + config, + name + } + } else { + return { + config: [], + name + } + } +} + +export const changeCurrentUploader = (type: string, config: IStringKeyMap, id?: string) => { + if (!type || !config) { + return + } + if (id) { + picgo.saveConfig({ + [`uploader.${type}.defaultId`]: id + }) + } + picgo.saveConfig({ + 'picBed.current': type, + 'picBed.uploader': type, + [`picBed.${type}`]: config + }) +} + +export const getUploaderConfigList = (type: string) => { + const currentUploaderConfig = picgo.getConfig(`uploader.${type}`) ?? {} + let configList = currentUploaderConfig.configList || [] + let defaultId = currentUploaderConfig.defaultId || '' + if (!configList) { + const res = upgradeUploaderConfig(type) + configList = res.configList + defaultId = res.defaultId + } + return { + configList, + defaultId + } +} + +/** + * delete uploader config by type & id + */ +export const deleteUploaderConfig = (type: string, id: string) => { + const { configList, defaultId } = getUploaderConfigList(type) + if (configList.length <= 1) { + return + } + const updatedConfigList = configList.filter((item: IStringKeyMap) => item._id !== id) + if (id === defaultId) { + changeCurrentUploader(type, updatedConfigList[0], updatedConfigList[0]._id) + } + picgo.saveConfig({ + [`uploader.${type}.configList`]: updatedConfigList + }) +} + +/** + * upgrade old uploader config to new format + */ +export const upgradeUploaderConfig = (type: string): { + configList: IStringKeyMap[] + defaultId: string +} => { + const uploaderConfig = picgo.getConfig(`picBed.${type}`) ?? {} + if (!uploaderConfig._id) { + Object.assign(uploaderConfig, completeUploaderMetaConfig(uploaderConfig)) + } + + const uploaderConfigList = [uploaderConfig] + picgo.saveConfig({ + [`uploader.${type}`]: { + configList: uploaderConfigList, + defaultId: uploaderConfig._id + }, + [`picBed.${type}`]: uploaderConfig + }) + return { + configList: uploaderConfigList, + defaultId: uploaderConfig._id + } +}