🚧 WIP: add uploader config list menu & rebuild multi-config communication way

This commit is contained in:
PiEgg 2022-12-31 20:44:19 +08:00
parent f0787d3ec2
commit 5969daedac
14 changed files with 247 additions and 53 deletions

View File

@ -23,6 +23,7 @@ CONFIG_THING: Config ${c}
FIND_NEW_VERSION: Find New Version FIND_NEW_VERSION: Find New Version
NO_MORE_NOTICE: No More Notice NO_MORE_NOTICE: No More Notice
SHOW_DEVTOOLS: Show Devtools SHOW_DEVTOOLS: Show Devtools
CURRENT_PICBED: Current Picbed
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -23,6 +23,7 @@ CONFIG_THING: 配置${c}
FIND_NEW_VERSION: 发现新版本 FIND_NEW_VERSION: 发现新版本
NO_MORE_NOTICE: 以后不再提醒 NO_MORE_NOTICE: 以后不再提醒
SHOW_DEVTOOLS: 打开开发者工具 SHOW_DEVTOOLS: 打开开发者工具
CURRENT_PICBED: 当前图床
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -23,6 +23,7 @@ CONFIG_THING: 設定${c}
FIND_NEW_VERSION: 發現新版本 FIND_NEW_VERSION: 發現新版本
NO_MORE_NOTICE: 以後不再提醒 NO_MORE_NOTICE: 以後不再提醒
SHOW_DEVTOOLS: 開啟開發者工具 SHOW_DEVTOOLS: 開啟開發者工具
CURRENT_PICBED: 當前圖床
# ---renderer i18n begin--- # ---renderer i18n begin---

View File

@ -9,11 +9,9 @@ import {
Notification Notification
} from 'electron' } from 'electron'
import uploader from 'apis/app/uploader' import uploader from 'apis/app/uploader'
import getPicBeds from '~/main/utils/getPicBeds'
import db, { GalleryDB } from '~/main/apis/core/datastore' import db, { GalleryDB } from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from '#/types/enum' import { IWindowList } from '#/types/enum'
import picgo from '@core/picgo'
import pasteTemplate from '~/main/utils/pasteTemplate' import pasteTemplate from '~/main/utils/pasteTemplate'
import pkg from 'root/package.json' import pkg from 'root/package.json'
import { ensureFilePath, handleCopyUrl } from '~/main/utils/common' import { ensureFilePath, handleCopyUrl } from '~/main/utils/common'
@ -21,28 +19,13 @@ import { privacyManager } from '~/main/utils/privacyManager'
// import { T } from '#/i18n' // import { T } from '#/i18n'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion' import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion'
import { buildPicBedListMenu } from '~/main/events/remotes/menu'
let contextMenu: Menu | null let contextMenu: Menu | null
let menu: Menu | null let menu: Menu | null
let tray: Tray | null let tray: Tray | null
export function createContextMenu () { export function createContextMenu () {
const picBeds = getPicBeds()
if (process.platform === 'darwin' || process.platform === 'win32') { if (process.platform === 'darwin' || process.platform === 'win32') {
const submenu = picBeds.filter(item => item.visible).map(item => { const submenu = buildPicBedListMenu()
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')
}
}
}
})
contextMenu = Menu.buildFromTemplate([ contextMenu = Menu.buildFromTemplate([
{ {
label: T('ABOUT'), label: T('ABOUT'),

View File

@ -36,7 +36,7 @@ import {
} from '~/main/apis/app/uploader/apis' } from '~/main/apis/app/uploader/apis'
import picgoCoreIPC from './picgoCoreIPC' import picgoCoreIPC from './picgoCoreIPC'
import { handleCopyUrl } from '~/main/utils/common' 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 path from 'path'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
@ -186,7 +186,7 @@ export default {
}) })
ipcMain.on(SHOW_UPLOAD_PAGE_MENU, () => { ipcMain.on(SHOW_UPLOAD_PAGE_MENU, () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)! const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildUploadPageMenu() const menu = buildPicBedListMenu()
menu.popup({ menu.popup({
window window
}) })

View File

@ -29,7 +29,8 @@ import {
OPEN_WINDOW, OPEN_WINDOW,
GET_LANGUAGE_LIST, GET_LANGUAGE_LIST,
SET_CURRENT_LANGUAGE, SET_CURRENT_LANGUAGE,
GET_CURRENT_LANGUAGE GET_CURRENT_LANGUAGE,
RPC_ACTIONS
} from '#/events/constants' } from '#/events/constants'
import { GalleryDB } from 'apis/core/datastore' 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 { export default {
listen () { listen () {
handleGetPluginList() handleGetPluginList()
@ -409,6 +414,7 @@ export default {
handleOpenFile() handleOpenFile()
handleOpenWindow() handleOpenWindow()
handleI18n() handleI18n()
handleRPCActions()
}, },
// TODO: separate to single file // TODO: separate to single file
handlePluginUninstall, handlePluginUninstall,

View File

@ -13,6 +13,7 @@ import { PICGO_CONFIG_PLUGIN, PICGO_HANDLE_PLUGIN_ING, PICGO_TOGGLE_PLUGIN, SHOW
import picgoCoreIPC from '~/main/events/picgoCoreIPC' import picgoCoreIPC from '~/main/events/picgoCoreIPC'
import { PicGo as PicGoCore } from 'picgo' import { PicGo as PicGoCore } from 'picgo'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { changeCurrentUploader } from '~/universal/utils/handleUploaderConfig'
interface GuiMenuItem { interface GuiMenuItem {
label: string label: string
@ -20,24 +21,7 @@ interface GuiMenuItem {
} }
const buildMiniPageMenu = () => { const buildMiniPageMenu = () => {
const picBeds = getPicBeds() const submenu = buildPicBedListMenu()
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 template = [ const template = [
{ {
label: T('OPEN_MAIN_WINDOW'), label: T('OPEN_MAIN_WINDOW'),
@ -128,26 +112,58 @@ const buildMainPageMenu = (win: BrowserWindow) => {
return Menu.buildFromTemplate(template) return Menu.buildFromTemplate(template)
} }
const buildUploadPageMenu = () => { const buildPicBedListMenu = () => {
const picBeds = getPicBeds() const picBeds = getPicBeds()
const currentPicBed = picgo.getConfig('picBed.uploader') 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<IUploaderConfig>('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 { return {
label: item.name, label: item.name,
type: 'radio', type: !hasSubmenu ? 'checkbox' : undefined,
checked: currentPicBed === item.type, checked: !hasSubmenu ? (currentPicBed === item.type) : undefined,
click () { submenu: hasSubmenu
picgo.saveConfig({ ? configList.map((config) => {
'picBed.current': item.type, return {
'picBed.uploader': item.type 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)) { : undefined,
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('syncPicBed') 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 // @ts-ignore
submenu = currentPicBedMenuItem.concat(submenu)
// @ts-ignore
return Menu.buildFromTemplate(submenu) return Menu.buildFromTemplate(submenu)
} }
@ -289,6 +305,6 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
export { export {
buildMiniPageMenu, buildMiniPageMenu,
buildMainPageMenu, buildMainPageMenu,
buildUploadPageMenu, buildPicBedListMenu,
buildPluginPageMenu buildPluginPageMenu
} }

View File

@ -1,7 +1,8 @@
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue } from 'vue-property-decorator'
import { ipcRenderer, IpcRendererEvent } from 'electron' 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 { uuid } from 'uuidv4'
import { IRPCActionType } from '~/universal/types/enum'
@Component @Component
export default class extends Vue { export default class extends Vue {
created () { created () {
@ -34,6 +35,23 @@ export default class extends Vue {
}) })
} }
/**
* trigger RPC action
*/
triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<T | undefined> {
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 () { forceUpdate () {
this.$bus.$emit(FORCE_UPDATE) this.$bus.$emit(FORCE_UPDATE)
} }

View File

@ -34,6 +34,7 @@ export const SHOW_MAIN_PAGE_DONATION = 'SHOW_MAIN_PAGE_DONATION'
export const FORCE_UPDATE = 'FORCE_UPDATE' export const FORCE_UPDATE = 'FORCE_UPDATE'
export const OPEN_WINDOW = 'OPEN_WINDOW' export const OPEN_WINDOW = 'OPEN_WINDOW'
export const GET_PICBEDS = 'GET_PICBEDS' export const GET_PICBEDS = 'GET_PICBEDS'
export const RPC_ACTIONS = 'RPC_ACTIONS'
// i18n // i18n
export const GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE' export const GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE'
export const GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST' export const GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST'

View File

@ -46,3 +46,10 @@ export enum IRemoteNoticeTriggerCount {
ONCE = 'ONCE', // default ONCE = 'ONCE', // default
ALWAYS = 'ALWAYS' ALWAYS = 'ALWAYS'
} }
/**
* renderer trigger action from main
*/
export enum IRPCActionType {
GET_PICBED_CONFIG_LIST = 'GET_PICBED_CONFIG_LIST',
}

View File

@ -24,6 +24,7 @@ interface ILocales {
FIND_NEW_VERSION: string FIND_NEW_VERSION: string
NO_MORE_NOTICE: string NO_MORE_NOTICE: string
SHOW_DEVTOOLS: string SHOW_DEVTOOLS: string
CURRENT_PICBED: string
CHOOSE_YOUR_DEFAULT_PICBED: string CHOOSE_YOUR_DEFAULT_PICBED: string
UPLOAD_AREA: string UPLOAD_AREA: string
GALLERY: string GALLERY: string

View File

@ -159,6 +159,22 @@ interface IPicGoPluginConfig {
[propName: string]: any [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 { interface IPluginMenuConfig {
name: string name: string
fullName?: string fullName?: string
@ -389,3 +405,17 @@ interface IRemoteNoticeButton {
interface IRemoteNoticeLocalCountStorage { interface IRemoteNoticeLocalCountStorage {
[id: string]: true | number [id: string]: true | number
} }
interface IUploaderListItemMetaInfo {
_id: string
_configName: string
_updatedAt: number
_createdAt: number
}
interface IUploaderConfig {
[picBedType: string]: {
configList: (IStringKeyMap & IUploaderListItemMetaInfo)[]
defaultId: string
}
}

View File

@ -43,3 +43,11 @@ export const enforceNumber = (num: number | string) => {
} }
export const isDev = process.env.NODE_ENV === 'development' 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
}

View File

@ -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<IStringKeyMap>(`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<IStringKeyMap>(`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
}
}