Feature(custom): refactor all main ipc event

This commit is contained in:
Kuingsmile
2024-06-12 23:38:17 +08:00
parent 106290f868
commit 5ddc182bd1
91 changed files with 1924 additions and 1806 deletions

View File

@@ -19,10 +19,9 @@ import db from '@/utils/db'
import { T } from '@/i18n/index'
import { store } from '@/store'
import { initTalkingData } from '@/utils/analytic'
import { getConfig, saveConfig, triggerRPC } from '@/utils/dataSender'
import { mainMixin } from '@/utils/mainMixin'
import { dragMixin } from '@/utils/mixin'
import { sendToMain } from '@/utils/common'
import { sendRPC, sendToMain, triggerRPC } from '@/utils/common'
webFrame.setVisualZoomLevelLimits(1, 1)
@@ -30,16 +29,14 @@ const app = createApp(App)
app.config.globalProperties.$$db = db
app.config.globalProperties.$T = T
app.config.globalProperties.getConfig = getConfig
app.config.globalProperties.triggerRPC = triggerRPC
app.config.globalProperties.saveConfig = saveConfig
app.config.globalProperties.sendRPC = sendRPC
app.config.globalProperties.sendToMain = sendToMain
app.mixin(mainMixin)
app.mixin(dragMixin)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(VueLazyLoad, {
error: `file://${__static.replace(/\\/g, '/')}/unknown-file-type.svg`
})
@@ -52,5 +49,4 @@ console.log(hljsCommon.highlightAuto('<h1>Highlight.js has been registered succe
app.use(hljsVuePlugin)
app.use(VueVideoPlayer)
app.mount('#app')
initTalkingData()

View File

@@ -3,9 +3,10 @@ import {
clipboard,
dialog,
Menu,
MenuItem,
MenuItemConstructorOptions,
nativeTheme,
Notification,
screen,
Tray
} from 'electron'
import fs from 'fs-extra'
@@ -29,23 +30,16 @@ import { configPaths } from '#/utils/configPaths'
import { IPasteStyle, IWindowList } from '#/types/enum'
import pkg from 'root/package.json'
import { hideMiniWindow, openMainWindow, openMiniWindow } from '~/utils/windowHelper'
let contextMenu: Menu | null
export function setDockMenu () {
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
const dockMenu = Menu.buildFromTemplate([
{
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
settingWindow!.show()
settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
click: openMainWindow
},
{
label: T('START_WATCH_CLIPBOARD'),
@@ -58,7 +52,7 @@ export function setDockMenu () {
})
setDockMenu()
},
enabled: !isListeningClipboard
visible: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
@@ -68,7 +62,7 @@ export function setDockMenu () {
clipboardPoll.removeAllListeners()
setDockMenu()
},
enabled: isListeningClipboard
visible: isListeningClipboard
}
])
app.dock.setMenu(dockMenu)
@@ -80,59 +74,27 @@ export function createMenu () {
{
label: 'PicList',
submenu: [
{
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show()
settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
},
{
label: T('RELOAD_APP'),
click () {
app.relaunch()
app.exit(0)
}
}
{ label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
{ label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } }
]
},
{
label: T('CHOOSE_DEFAULT_PICBED'),
type: 'submenu',
// @ts-ignore
submenu
},
{ label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu },
{
label: 'Edit',
// @ts-ignore
submenu: [
// @ts-ignore
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
// @ts-ignore
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
{ label: 'Undo', accelerator: 'CmdOrCtrl+Z', role: 'undo' },
{ label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' },
{ type: 'separator' },
// @ts-ignore
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
// @ts-ignore
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
// @ts-ignore
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
// @ts-ignore
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' }
{ label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' },
{ label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' },
{ label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' },
{ label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }
]
},
{
label: T('QUIT'),
submenu: [
{
label: T('QUIT'),
role: 'quit'
}
{ label: T('QUIT'), role: 'quit' }
]
}
])
@@ -142,94 +104,39 @@ export function createMenu () {
export function createContextMenu () {
const ClipboardWatcher = clipboardPoll
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const isMiniWindowVisible = windowManager.has(IWindowList.MINI_WINDOW) && windowManager.get(IWindowList.MINI_WINDOW)!.isVisible()
const startWatchClipboard = () => {
db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed')
uploadClipboardFiles()
})
createContextMenu()
}
const stopWatchClipboard = () => {
db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners()
createContextMenu()
}
if (process.platform === 'darwin' || process.platform === 'win32') {
const submenu = buildPicBedListMenu()
const template = [
{
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show()
settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
},
{
label: T('CHOOSE_DEFAULT_PICBED'),
type: 'submenu',
// @ts-ignore
submenu
},
{
label: T('START_WATCH_CLIPBOARD'),
click () {
db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed')
uploadClipboardFiles()
})
createContextMenu()
},
enabled: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
click () {
db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners()
createContextMenu()
},
enabled: isListeningClipboard
},
{
label: T('RELOAD_APP'),
click () {
app.relaunch()
app.exit(0)
}
},
// @ts-ignore
{
role: 'quit',
label: T('QUIT')
}
] as any
const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [
{ label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
{ label: T('CHOOSE_DEFAULT_PICBED'), type: 'submenu', submenu },
{ label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard },
{ label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard },
{ label: T('RELOAD_APP'), click () { app.relaunch(); app.exit(0) } },
{ label: T('QUIT'), role: 'quit' }
]
if (process.platform === 'win32') {
template.splice(2, 0,
{
label: T('OPEN_MINI_WINDOW'),
click () {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners()
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true)
}
const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else {
miniWindow.setPosition(width - 100, height - 100)
}
const setPositionFunc = () => {
const position = miniWindow.getPosition()
db.set(configPaths.settings.miniWindowPosition, position)
}
miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc)
miniWindow.show()
miniWindow.focus()
const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
}
}
}
{ label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible },
{ label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible }
)
}
contextMenu = Menu.buildFromTemplate(template)
@@ -242,70 +149,11 @@ export function createContextMenu () {
// 目前的实现无法正常工作
contextMenu = Menu.buildFromTemplate([
{
label: T('OPEN_MAIN_WINDOW'),
click () {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show()
settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
},
{
label: T('OPEN_MINI_WINDOW'),
click () {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners()
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true)
}
const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else {
miniWindow.setPosition(width - 100, height - 100)
}
const setPositionFunc = () => {
const position = miniWindow.getPosition()
db.set(configPaths.settings.miniWindowPosition, position)
}
miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc)
miniWindow.show()
miniWindow.focus()
const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
}
}
},
{
label: T('START_WATCH_CLIPBOARD'),
click () {
db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed')
uploadClipboardFiles()
})
createContextMenu()
},
enabled: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
click () {
db.set(configPaths.settings.isListeningClipboard, false)
ClipboardWatcher.stopListening()
ClipboardWatcher.removeAllListeners()
createContextMenu()
},
enabled: isListeningClipboard
},
{ label: T('OPEN_MAIN_WINDOW'), click: openMainWindow },
{ label: T('OPEN_MINI_WINDOW'), click () { openMiniWindow(false) }, visible: !isMiniWindowVisible },
{ label: T('HIDE_MINI_WINDOW'), click: hideMiniWindow, visible: isMiniWindowVisible },
{ label: T('START_WATCH_CLIPBOARD'), click: startWatchClipboard, visible: !isListeningClipboard },
{ label: T('STOP_WATCH_CLIPBOARD'), click: stopWatchClipboard, visible: isListeningClipboard },
{
label: T('ABOUT'),
click () {
@@ -317,11 +165,7 @@ export function createContextMenu () {
})
}
},
// @ts-ignore
{
role: 'quit',
label: T('QUIT')
}
{ label: T('QUIT'), role: 'quit' }
])
}
}

View File

@@ -4,26 +4,18 @@ import {
} from 'electron'
import fs from 'fs-extra'
import { cloneDeep } from 'lodash'
import path from 'path'
import { ISftpPlistConfig } from 'piclist'
import picgo from '@core/picgo'
import db, { GalleryDB } from '@core/datastore'
import GuiApi from 'apis/gui'
import uploader from 'apis/app/uploader'
import windowManager from 'apis/app/window/windowManager'
import { T } from '~/i18n/index'
import { handleCopyUrl, handleUrlEncodeWithSetting } from '~/utils/common'
import pasteTemplate from '~/utils/pasteTemplate'
import SSHClient from '~/utils/sshClient'
import ALLApi from '@/apis/allApi'
import { getRawData } from '@/utils/common'
import { IPasteStyle, IWindowList } from '#/types/enum'
import { picBedsCanbeDeleted } from '#/utils/static'
import { configPaths } from '#/utils/configPaths'
const handleClipboardUploading = async (): Promise<false | ImgInfo[]> => {
@@ -129,62 +121,3 @@ export const uploadChoosedFiles = async (webContents: WebContents, files: IFileW
return []
}
}
async function deleteSFTPFile (config: ISftpPlistConfig, fileName: string) {
try {
const client = SSHClient.instance
await client.connect(config)
const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
const remote = path.join(uploadPath, fileName)
const deleteResult = await client.deleteFileSFTP(config, remote)
client.close()
return deleteResult
} catch (err: any) {
picgo.log.error(err)
return false
}
}
export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> => {
const result = []
for (const item of list) {
if (item.id) {
try {
const dbStore = GalleryDB.getInstance()
const file = await dbStore.getById(item.id)
await dbStore.removeById(item.id)
if (await picgo.getConfig(configPaths.settings.deleteCloudFile)) {
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
const noteFunc = (value: boolean) => {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T(value ? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED' : 'GALLERY_SYNC_DELETE_NOTICE_FAILED')
})
notification.show()
}
if (item.type === 'sftpplist') {
const { fileName, config } = item
setTimeout(() => {
deleteSFTPFile(getRawData(config), fileName || '').then(noteFunc)
}, 0)
} else {
setTimeout(() => {
ALLApi.delete(item).then(noteFunc)
}, 0)
}
}
}
setTimeout(() => {
picgo.emit('remove', [file], GuiApi.getInstance())
}, 500)
result.push(true)
} catch (e) {
result.push(false)
}
}
}
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return result
}

View File

@@ -6,7 +6,7 @@ import {
Notification,
WebContents
} from 'electron'
import fse from 'fs-extra'
import fs from 'fs-extra'
import util from 'util'
import path from 'path'
import { IPicGo } from 'piclist'
@@ -26,7 +26,7 @@ import {
RENAME_FILE_NAME,
TALKING_DATA_EVENT
} from '#/events/constants'
import { IWindowList } from '#/types/enum'
import { ICOREBuildInEvent, IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { CLIPBOARD_IMAGE_FOLDER } from '#/utils/static'
@@ -61,21 +61,22 @@ const handleTalkingData = (webContents: WebContents, options: IAnalyticsData) =>
class Uploader {
private webContents: WebContents | null = null
// private uploading: boolean = false
constructor () {
this.init()
}
init () {
picgo.on('notification', (message: Electron.NotificationConstructorOptions | undefined) => {
picgo.on(ICOREBuildInEvent.NOTIFICATION, (message: Electron.NotificationConstructorOptions | undefined) => {
const notification = new Notification(message)
notification.show()
})
picgo.on('uploadProgress', (progress: any) => {
picgo.on(ICOREBuildInEvent.UPLOAD_PROGRESS, (progress: any) => {
this.webContents?.send('uploadProgress', progress)
})
picgo.on('beforeTransform', () => {
picgo.on(ICOREBuildInEvent.BEFORE_TRANSFORM, () => {
if (db.get(configPaths.settings.uploadNotification)) {
const notification = new Notification({
title: T('UPLOAD_PROGRESS'),
@@ -84,6 +85,7 @@ class Uploader {
notification.show()
}
})
picgo.helper.beforeUploadPlugins.register('renameFn', {
handle: async (ctx: IPicGo) => {
const rename = db.get(configPaths.settings.rename)
@@ -150,7 +152,7 @@ class Uploader {
return false
} finally {
if (filePath) {
fse.remove(filePath)
fs.remove(filePath)
}
}
}

View File

@@ -12,7 +12,6 @@ import {
import bus from '@core/bus'
import { CREATE_APP_MENU } from '@core/bus/constants'
import db from '@core/datastore'
import picgo from '@core/picgo'
import { T } from '~/i18n'
@@ -25,16 +24,14 @@ const windowList = new Map<IWindowList, IWindowListItem>()
const handleWindowParams = (windowURL: string) => windowURL
const getDefaultWindowSizes = (): { width: number, height: number } => {
const mainWindowWidth = picgo.getConfig<any>(configPaths.settings.mainWindowWidth)
const mainWindowHeight = picgo.getConfig<any>(configPaths.settings.mainWindowHeight)
const [mainWindowWidth, mainWindowHeight] = db.get([configPaths.settings.mainWindowWidth, configPaths.settings.mainWindowHeight])
return {
width: mainWindowWidth || 1200,
height: mainWindowHeight || 800
}
}
const defaultWindowWidth = getDefaultWindowSizes().width
const defaultWindowHeight = getDefaultWindowSizes().height
const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
const trayWindowOptions = {
height: 350,

View File

@@ -6,6 +6,7 @@ import { IWindowList } from '#/types/enum'
class WindowManager implements IWindowManager {
#windowMap: Map<IWindowList | string, BrowserWindow> = new Map()
#windowIdMap: Map<number, IWindowList | string> = new Map()
create (name: IWindowList) {
const windowConfig: IWindowListItem = windowList.get(name)!
if (windowConfig.isValid) {

View File

@@ -5,6 +5,8 @@ import { dbPathChecker, dbPathDir, getGalleryDBPath } from '@core/datastore/dbCh
import { T } from '~/i18n'
import { configPaths } from '#/utils/configPaths'
import { IJSON } from '@picgo/store/dist/types'
import { IConfig } from 'piclist'
const STORE_PATH = dbPathDir()
@@ -16,6 +18,7 @@ export const DB_PATH: string = getGalleryDBPath().dbPath
class ConfigStore {
#db: JSONStore
constructor () {
this.#db = new JSONStore(CONFIG_PATH)
@@ -40,34 +43,54 @@ class ConfigStore {
this.read()
}
flush () {
this.#db = new JSONStore(CONFIG_PATH)
read (flush?: boolean): IJSON {
return this.#db.read(flush)
}
read () {
this.#db.read()
return this.#db
}
get (key = ''): any {
getSingle (key = ''): any {
if (key === '') {
return this.#db.read()
return this.#db.read(true)
}
this.read(true)
return this.#db.get(key)
}
get (key: string): any
get (key: string[]): any[]
get (key: string | string[] = ''): any {
if (Array.isArray(key)) {
return key.map(k => this.getSingle(k))
}
return this.getSingle(key)
}
set (key: string, value: any): void {
this.read(true)
return this.#db.set(key, value)
}
has (key: string) {
this.read(true)
return this.#db.has(key)
}
unset (key: string, value: any): boolean {
this.read(true)
return this.#db.unset(key, value)
}
saveConfig (config: Partial<IConfig>): void {
Object.keys(config).forEach((name: string) => {
this.set(name, config[name])
})
}
removeConfig (config: IConfig): void {
Object.keys(config).forEach((name: string) => {
this.unset(name, config[name])
})
}
getConfigPath () {
return CONFIG_PATH
}

View File

@@ -22,7 +22,7 @@ picgo.GUI_VERSION = global.PICGO_GUI_VERSION
const originPicGoSaveConfig = picgo.saveConfig.bind(picgo)
function flushDB () {
db.flush()
db.read(true)
}
const debounced = debounce(flushDB, 1000)

View File

@@ -65,7 +65,7 @@ class GuiApi implements IGuiApi {
await this.showSettingWindow()
this.getWebcontentsByWindowId(this.settingWindowId)?.send(SHOW_INPUT_BOX, options)
return new Promise<string>((resolve) => {
ipcMain.once(SHOW_INPUT_BOX, (event: Event, value: string) => {
ipcMain.once(SHOW_INPUT_BOX, (_: Event, value: string) => {
resolve(value)
})
})

View File

@@ -1,388 +0,0 @@
import {
app,
ipcMain,
shell,
Notification,
IpcMainEvent,
BrowserWindow,
screen,
IpcMainInvokeEvent
} from 'electron'
import fs from 'fs-extra'
import path from 'path'
import { ISftpPlistConfig } from 'piclist'
import bus from '@core/bus'
import logger from '@core/picgo/logger'
import db, { GalleryDB } from '@core/datastore'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import uploader from 'apis/app/uploader'
import {
uploadClipboardFiles,
uploadChoosedFiles
} from 'apis/app/uploader/apis'
import windowManager from 'apis/app/window/windowManager'
import { T } from '~/i18n'
import server from '~/server'
import picgoCoreIPC from '~/events/picgoCoreIPC'
import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildPicBedListMenu } from '~/events/remotes/menu'
import { handleCopyUrl, generateShortUrl, setTrayToolTip } from '~/utils/common'
import { removeFileFromS3InMain, removeFileFromDogeInMain, removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
import getPicBeds from '~/utils/getPicBeds'
import pasteTemplate from '~/utils/pasteTemplate'
import SSHClient from '~/utils/sshClient'
import { uploadFile, downloadFile } from '~/utils/syncSettings'
import webServer from '~/server/webServer'
import {
TOGGLE_SHORTKEY_MODIFIED_MODE,
OPEN_DEVTOOLS,
SHOW_MINI_PAGE_MENU,
MINIMIZE_WINDOW,
CLOSE_WINDOW,
SHOW_MAIN_PAGE_MENU,
SHOW_UPLOAD_PAGE_MENU,
OPEN_USER_STORE_FILE,
OPEN_URL,
RELOAD_APP,
SHOW_PLUGIN_PAGE_MENU,
SET_MINI_WINDOW_POS,
GET_PICBEDS,
HIDE_DOCK
} from '#/events/constants'
import { configPaths } from '#/utils/configPaths'
import { ILogType, IPasteStyle, IWindowList } from '#/types/enum'
const STORE_PATH = app.getPath('userData')
const commonConfigList = ['data.json', 'data.bak.json']
const manageConfigList = ['manage.json', 'manage.bak.json']
export default {
listen () {
picgoCoreIPC.listen()
// Upload Related IPC
// from macOS tray
ipcMain.on('uploadClipboardFiles', async () => {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
// macOS use builtin clipboard is OK
const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard()
if (img !== false) {
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: T('UPLOAD_SUCCEED'),
body: img[0].imgUrl!
// icon: file[0]
// icon: img[0].imgUrl
})
notification.show()
}
await GalleryDB.getInstance().insert(img[0])
trayWindow.webContents.send('clipboardFiles', [])
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
}
}
trayWindow.webContents.send('uploadFiles')
})
ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
uploadClipboardFiles()
})
ipcMain.on('uploadChoosedFiles', async (evt: IpcMainEvent, files: IFileWithPath[]) => {
return uploadChoosedFiles(evt.sender, files)
})
ipcMain.on('setTrayToolTip', (_: IpcMainEvent, title: string) => {
setTrayToolTip(title)
})
// ShortKey Related IPC
ipcMain.on('updateShortKey', (evt: IpcMainEvent, item: IShortKeyConfig, oldKey: string, from: string) => {
const result = shortKeyHandler.updateShortKey(item, oldKey, from)
evt.sender.send('updateShortKeyResponse', result)
if (result) {
const notification = new Notification({
title: T('OPERATION_SUCCEED'),
body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: T('OPERATION_FAILED'),
body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
})
notification.show()
}
})
ipcMain.on('bindOrUnbindShortKey', (_: IpcMainEvent, item: IShortKeyConfig, from: string) => {
const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
if (result) {
const notification = new Notification({
title: T('OPERATION_SUCCEED'),
body: T('TIPS_SHORTCUT_MODIFIED_SUCCEED')
})
notification.show()
} else {
const notification = new Notification({
title: T('OPERATION_FAILED'),
body: T('TIPS_SHORTCUT_MODIFIED_CONFLICT')
})
notification.show()
}
})
// Gallery image cloud delete IPC
ipcMain.on('logDeleteMsg', async (_: IpcMainEvent, msg: string, logLevel: ILogType) => {
logger[logLevel](msg)
})
ipcMain.handle('delete-sftp-file', async (_: IpcMainInvokeEvent, config: ISftpPlistConfig, fileName: string) => {
try {
const client = SSHClient.instance
await client.connect(config)
const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
const remote = path.join(uploadPath, fileName)
const deleteResult = await client.deleteFileSFTP(config, remote)
client.close()
return deleteResult
} catch (err: any) {
logger.error(err)
return false
}
})
ipcMain.handle('delete-aws-s3-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromS3InMain(configMap)
return result
})
ipcMain.handle('delete-doge-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromDogeInMain(configMap)
return result
})
ipcMain.handle('delete-huaweicloud-file', async (_: IpcMainInvokeEvent, configMap: IStringKeyMap) => {
const result = await removeFileFromHuaweiInMain(configMap)
return result
})
// migrate from PicGo
ipcMain.handle('migrateFromPicGo', async () => {
const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo')
const files = [
'data.json',
'data.bak.json',
'picgo.db',
'picgo.bak.db'
]
try {
await Promise.all(files.map(async file => {
const sourcePath = path.join(picGoConfigPath, file)
const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist'))
await fs.remove(targetPath)
await fs.copy(sourcePath, targetPath, { overwrite: true })
}
))
return true
} catch (err: any) {
logger.error(err)
return false
}
})
// PicList Setting page IPC
ipcMain.on('autoStart', (_: IpcMainEvent, val: boolean) => {
app.setLoginItemSettings({
openAtLogin: val
})
})
ipcMain.handle('getShortUrl', async (_: IpcMainInvokeEvent, url: string) => {
const shortUrl = await generateShortUrl(url)
return shortUrl
})
ipcMain.handle('uploadCommonConfig', async () => {
return await uploadFile(commonConfigList)
})
ipcMain.handle('downloadCommonConfig', async () => {
return await downloadFile(commonConfigList)
})
ipcMain.handle('uploadManageConfig', async () => {
return await uploadFile(manageConfigList)
})
ipcMain.handle('downloadManageConfig', async () => {
return await downloadFile(manageConfigList)
})
ipcMain.handle('uploadAllConfig', async () => {
return await uploadFile([...commonConfigList, ...manageConfigList])
})
ipcMain.handle('downloadAllConfig', async () => {
return await downloadFile([...commonConfigList, ...manageConfigList])
})
ipcMain.on('toggleMainWindowAlwaysOnTop', () => {
const mainWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
const isAlwaysOnTop = mainWindow.isAlwaysOnTop()
mainWindow.setAlwaysOnTop(!isAlwaysOnTop)
})
// Window operation API
ipcMain.on('openSettingWindow', () => {
windowManager.get(IWindowList.SETTING_WINDOW)!.show()
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
if (autoCloseMiniWindow) {
if (windowManager.has(IWindowList.MINI_WINDOW)) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
})
ipcMain.on('openManualWindow', () => {
windowManager.get(IWindowList.MANUAL_WINDOW)!.show()
})
ipcMain.on('openMiniWindow', () => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
miniWindow.removeAllListeners()
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true)
}
const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else {
miniWindow.setPosition(width - 100, height - 100)
}
const setPositionFunc = () => {
const position = miniWindow.getPosition()
db.set(configPaths.settings.miniWindowPosition, position)
}
miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc)
miniWindow.show()
miniWindow.focus()
settingWindow.hide()
})
ipcMain.on('updateMiniIcon', (_: IpcMainEvent, iconPath: string) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.webContents.send('updateMiniIcon', iconPath)
})
ipcMain.on('miniWindowOntop', (_: IpcMainEvent, val: boolean) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.setAlwaysOnTop(val)
})
ipcMain.on('refreshSettingWindow', () => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.webContents.reloadIgnoringCache()
})
ipcMain.on(GET_PICBEDS, (evt: IpcMainEvent) => {
const picBeds = getPicBeds()
evt.sender.send(GET_PICBEDS, picBeds)
// evt.returnValue = picBeds
})
ipcMain.on(TOGGLE_SHORTKEY_MODIFIED_MODE, (_: IpcMainEvent, val: boolean) => {
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
})
ipcMain.on('updateServer', () => {
server.restart()
})
ipcMain.on('stopWebServer', () => {
webServer.stop()
})
ipcMain.on('restartWebServer', () => {
webServer.restart()
})
ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => {
event.sender.openDevTools()
})
// menu & window methods
ipcMain.on(SHOW_MINI_PAGE_MENU, () => {
const window = windowManager.get(IWindowList.MINI_WINDOW)!
const menu = buildMiniPageMenu()
menu.popup({
window
})
})
ipcMain.on(SHOW_MAIN_PAGE_MENU, () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildMainPageMenu(window)
menu.popup({
window
})
})
ipcMain.on(SHOW_UPLOAD_PAGE_MENU, () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildPicBedListMenu()
menu.popup({
window
})
})
ipcMain.on(SHOW_PLUGIN_PAGE_MENU, (_: IpcMainEvent, plugin: IPicGoPlugin) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildPluginPageMenu(plugin)
menu.popup({
window
})
})
ipcMain.on(MINIMIZE_WINDOW, () => {
const window = BrowserWindow.getFocusedWindow()
window?.minimize()
})
ipcMain.on(CLOSE_WINDOW, () => {
const window = BrowserWindow.getFocusedWindow()
if (process.platform === 'linux') {
window?.hide()
} else {
window?.close()
}
})
ipcMain.on(OPEN_USER_STORE_FILE, (_: IpcMainEvent, filePath: string) => {
const abFilePath = path.join(STORE_PATH, filePath)
shell.openPath(abFilePath)
})
ipcMain.on(OPEN_URL, (_: IpcMainEvent, url: string) => {
shell.openExternal(url)
})
ipcMain.on(RELOAD_APP, () => {
app.relaunch()
app.exit(0)
})
ipcMain.on(SET_MINI_WINDOW_POS, (_: IpcMainEvent, pos: IMiniWindowPos) => {
const window = BrowserWindow.getFocusedWindow()
window?.setBounds(pos)
})
ipcMain.on(HIDE_DOCK, (_: IpcMainEvent, val: boolean) => {
if (val) {
app.dock.hide()
} else {
app.dock.show()
}
})
},
dispose () {}
}

View File

@@ -1,459 +0,0 @@
import {
dialog,
shell,
IpcMainEvent,
ipcMain,
clipboard
} from 'electron'
import fs from 'fs-extra'
import path from 'path'
import { IGuiMenuItem, PicGo as PicGoCore } from 'piclist'
import { IObject, IFilter } from '@picgo/store/dist/types'
import picgo from '@core/picgo'
import { GalleryDB } from '@core/datastore'
import { dbPathChecker } from '@core/datastore/dbChecker'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import windowManager from 'apis/app/window/windowManager'
import GuiApi from 'apis/gui'
import { showNotification } from '~/utils/common'
import pasteTemplate from '~/utils/pasteTemplate'
import { i18nManager, T } from '~/i18n'
import { rpcServer } from '~/events/rpc'
import {
PICGO_SAVE_CONFIG,
PICGO_GET_CONFIG,
PICGO_GET_DB,
PICGO_INSERT_DB,
PICGO_INSERT_MANY_DB,
PICGO_UPDATE_BY_ID_DB,
PICGO_GET_BY_ID_DB,
PICGO_REMOVE_BY_ID_DB,
PICGO_OPEN_FILE,
PICGO_OPEN_DIRECTORY,
PASTE_TEXT,
OPEN_WINDOW,
GET_LANGUAGE_LIST,
SET_CURRENT_LANGUAGE,
GET_CURRENT_LANGUAGE,
PICGO_GET_CONFIG_SYNC
} from '#/events/constants'
import { configPaths } from '#/utils/configPaths'
import { IPasteStyle, IPicGoHelperType, IWindowList } from '#/types/enum'
import { handleStreamlinePluginName, simpleClone } from '#/utils/common'
// eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
// const PluginHandler = requireFunc('picgo/lib/PluginHandler').default
const STORE_PATH = path.dirname(dbPathChecker())
// const CONFIG_PATH = path.join(STORE_PATH, '/data.json')
interface GuiMenuItem {
label: string
handle: (arg0: PicGoCore, arg1: GuiApi) => Promise<void>
}
// get uploader or transformer config
const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => {
let config: any[] = []
if (name === '') {
return config
} else {
const handler = ctx.helper[type].get(name)
if (handler) {
if (handler.config) {
config = handler.config(ctx)
}
}
return config
}
}
const handleConfigWithFunction = (config: any[]) => {
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()
}
}
return config
}
const getPluginList = (): IPicGoPlugin[] => {
const pluginList = picgo.pluginLoader.getFullList()
const list = []
for (const i in pluginList) {
const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
const uploaderName = plugin.uploader || ''
const transformerName = plugin.transformer || ''
let menu: Omit<IGuiMenuItem, 'handle'>[] = []
if (plugin.guiMenu) {
menu = plugin.guiMenu(picgo).map(item => ({
label: item.label
}))
}
let gui = false
if (pluginPKG.keywords && pluginPKG.keywords.length > 0) {
if (pluginPKG.keywords.includes('picgo-gui-plugin')) {
gui = true
}
}
const obj: IPicGoPlugin = {
name: handleStreamlinePluginName(pluginList[i]),
fullName: pluginList[i],
author: pluginPKG.author.name || pluginPKG.author,
description: pluginPKG.description,
logo: 'file://' + path.join(pluginPath, 'logo.png').split(path.sep).join('/'),
version: pluginPKG.version,
gui,
config: {
plugin: {
fullName: pluginList[i],
name: handleStreamlinePluginName(pluginList[i]),
config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : []
},
uploader: {
name: uploaderName,
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader, picgo))
},
transformer: {
name: transformerName,
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer, picgo))
}
},
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
homepage: pluginPKG.homepage ? pluginPKG.homepage : '',
guiMenu: menu,
ing: false
}
list.push(obj)
}
return list
}
const handleGetPluginList = () => {
ipcMain.on('getPluginList', (event: IpcMainEvent) => {
try {
const list = simpleClone(getPluginList())
// here can just send JS Object not function
// or will cause [Failed to serialize arguments] error
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
picgo.log.error(e)
}
})
}
const handlePluginInstall = () => {
ipcMain.on('installPlugin', async (event: IpcMainEvent, fullName: string) => {
const dispose = handleNPMError()
const res = await picgo.pluginHandler.install([fullName])
event.sender.send('installPlugin', {
success: res.success,
body: fullName,
errMsg: res.success ? '' : res.body
})
if (res.success) {
shortKeyHandler.registerPluginShortKey(res.body[0])
} else {
showNotification({
title: T('PLUGIN_INSTALL_FAILED'),
body: res.body as string
})
}
event.sender.send('hideLoading')
dispose()
})
}
const handlePluginUninstall = async (fullName: string) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const dispose = handleNPMError()
const res = await picgo.pluginHandler.uninstall([fullName])
if (res.success) {
window.webContents.send('uninstallSuccess', res.body[0])
shortKeyHandler.unregisterPluginShortKey(res.body[0])
} else {
showNotification({
title: T('PLUGIN_UNINSTALL_FAILED'),
body: res.body as string
})
}
window.webContents.send('hideLoading')
dispose()
}
const handlePluginUpdate = async (fullName: string | string[]) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const dispose = handleNPMError()
const res = await picgo.pluginHandler.update(typeof fullName === 'string' ? [fullName] : fullName)
if (res.success) {
window.webContents.send('updateSuccess', res.body[0])
} else {
showNotification({
title: T('PLUGIN_UPDATE_FAILED'),
body: res.body as string
})
}
window.webContents.send('hideLoading')
dispose()
}
const handleUpdateAllPlugin = () => {
ipcMain.on('updateAllPlugin', async (_: IpcMainEvent, list: string[]) => {
handlePluginUpdate(list)
})
}
const handleNPMError = (): IDispose => {
const handler = (msg: string) => {
if (msg === 'NPM is not installed') {
dialog.showMessageBox({
title: T('TIPS_ERROR'),
message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'),
buttons: ['Yes']
}).then((res) => {
if (res.response === 0) {
shell.openExternal('https://nodejs.org/')
}
})
}
}
picgo.once('failed', handler)
return () => picgo.off('failed', handler)
}
const handleGetPicBedConfig = () => {
ipcMain.on('getPicBedConfig', (event: IpcMainEvent, 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)
event.sender.send('getPicBedConfig', config, name)
} else {
event.sender.send('getPicBedConfig', [], name)
}
})
}
// TODO: remove it
const handlePluginActions = () => {
ipcMain.on('pluginActions', (_: IpcMainEvent, name: string, label: string) => {
const plugin = picgo.pluginLoader.getPlugin(name)
if (plugin?.guiMenu?.(picgo)?.length) {
const menu: GuiMenuItem[] = plugin.guiMenu(picgo)
menu.forEach(item => {
if (item.label === label) {
item.handle(picgo, GuiApi.getInstance())
}
})
}
})
}
const handleRemoveFiles = () => {
ipcMain.on('removeFiles', (_: IpcMainEvent, files: ImgInfo[]) => {
setTimeout(() => {
picgo.emit('remove', files, GuiApi.getInstance())
}, 500)
})
}
const handlePicGoSaveConfig = () => {
ipcMain.on(PICGO_SAVE_CONFIG, (_: IpcMainEvent, data: IObj) => {
picgo.saveConfig(data)
})
}
const handlePicGoGetConfig = () => {
ipcMain.handle(PICGO_GET_CONFIG, (_, key: string | undefined) => {
return picgo.getConfig(key)
})
}
const handlePicGoGetConfigSync = () => {
ipcMain.on(PICGO_GET_CONFIG_SYNC, (event: IpcMainEvent, key: string | undefined) => {
const result = picgo.getConfig(key)
event.returnValue = result
})
}
const handleImportLocalPlugin = () => {
ipcMain.on('importLocalPlugin', async (event: IpcMainEvent) => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
const res = await dialog.showOpenDialog(settingWindow, {
properties: ['openDirectory']
})
const filePaths = res.filePaths
if (filePaths.length > 0) {
const res = await picgo.pluginHandler.install(filePaths)
if (res.success) {
try {
const list = simpleClone(getPluginList())
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
}
showNotification({
title: T('PLUGIN_IMPORT_SUCCEED'),
body: ''
})
} else {
showNotification({
title: T('PLUGIN_IMPORT_FAILED'),
body: res.body as string
})
}
}
event.sender.send('hideLoading')
})
}
const handlePicGoGalleryDB = () => {
ipcMain.on(PICGO_GET_DB, async (event: IpcMainEvent, filter: IFilter, callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.get(filter)
event.sender.send(PICGO_GET_DB, res, callbackId)
})
ipcMain.on(PICGO_INSERT_DB, async (event: IpcMainEvent, value: IObject, callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.insert(value)
event.sender.send(PICGO_INSERT_DB, res, callbackId)
})
ipcMain.on(PICGO_INSERT_MANY_DB, async (event: IpcMainEvent, value: IObject[], callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.insertMany(value)
event.sender.send(PICGO_INSERT_MANY_DB, res, callbackId)
})
ipcMain.on(PICGO_UPDATE_BY_ID_DB, async (event: IpcMainEvent, id: string, value: IObject[], callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.updateById(id, value)
event.sender.send(PICGO_UPDATE_BY_ID_DB, res, callbackId)
})
ipcMain.on(PICGO_GET_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.getById(id)
event.sender.send(PICGO_GET_BY_ID_DB, res, callbackId)
})
ipcMain.on(PICGO_REMOVE_BY_ID_DB, async (event: IpcMainEvent, id: string, callbackId: string) => {
const dbStore = GalleryDB.getInstance()
const res = await dbStore.removeById(id)
event.sender.send(PICGO_REMOVE_BY_ID_DB, res, callbackId)
})
ipcMain.handle(PASTE_TEXT, async (_, item: ImgInfo, copy = true) => {
const pasteStyle = picgo.getConfig<IPasteStyle>(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const customLink = picgo.getConfig<string>(configPaths.settings.customLink)
const txt = await pasteTemplate(pasteStyle, item, customLink)
if (copy) {
clipboard.writeText(txt)
}
return txt
})
}
const handleOpenFile = () => {
ipcMain.on(PICGO_OPEN_FILE, (event: IpcMainEvent, fileName: string) => {
const abFilePath = path.join(STORE_PATH, fileName)
if (!fs.existsSync(abFilePath)) {
fs.writeFileSync(abFilePath, '')
}
shell.openPath(abFilePath)
})
}
const handleOpenDirectory = () => {
ipcMain.on(PICGO_OPEN_DIRECTORY, (event: IpcMainEvent, dirPath?: string, inStorePath: boolean = true) => {
if (inStorePath) {
dirPath = path.join(STORE_PATH, dirPath || '')
}
if (!dirPath || !fs.existsSync(dirPath)) {
return
}
shell.openPath(dirPath)
})
}
const handleOpenWindow = () => {
ipcMain.on(OPEN_WINDOW, (event: IpcMainEvent, windowName: IWindowList) => {
const window = windowManager.get(windowName)
if (window) {
window.show()
}
})
}
const handleI18n = () => {
ipcMain.on(GET_LANGUAGE_LIST, (event: IpcMainEvent) => {
event.sender.send(GET_LANGUAGE_LIST, i18nManager.languageList)
})
ipcMain.on(SET_CURRENT_LANGUAGE, (event: IpcMainEvent, language: string) => {
i18nManager.setCurrentLanguage(language)
const { lang, locales } = i18nManager.getCurrentLocales()
picgo.i18n.setLanguage(lang)
if (process.platform === 'darwin') {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
trayWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
}
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
settingWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
if (windowManager.has(IWindowList.MINI_WINDOW)) {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)
miniWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
}
// event.sender.send(SET_CURRENT_LANGUAGE, lang, locales)
})
ipcMain.on(GET_CURRENT_LANGUAGE, (event: IpcMainEvent) => {
const { lang, locales } = i18nManager.getCurrentLocales()
event.sender.send(GET_CURRENT_LANGUAGE, lang, locales)
})
}
const handleRPCActions = () => {
rpcServer.start()
}
export default {
listen () {
handleGetPluginList()
handlePluginInstall()
handleGetPicBedConfig()
handlePluginActions()
handleRemoveFiles()
handlePicGoSaveConfig()
handlePicGoGetConfig()
handlePicGoGetConfigSync()
handlePicGoGalleryDB()
handleImportLocalPlugin()
handleUpdateAllPlugin()
handleOpenFile()
handleOpenDirectory()
handleOpenWindow()
handleI18n()
handleRPCActions()
},
// TODO: separate to single file
handlePluginUninstall,
handlePluginUpdate
}

View File

@@ -3,7 +3,9 @@ import {
dialog,
BrowserWindow,
Menu,
shell
shell,
MenuItemConstructorOptions,
MenuItem
} from 'electron'
import { PicGo as PicGoCore } from 'piclist'
@@ -16,7 +18,7 @@ import {
import windowManager from 'apis/app/window/windowManager'
import GuiApi from 'apis/gui'
import picgoCoreIPC from '~/events/picgoCoreIPC'
import { handlePluginUninstall, handlePluginUpdate } from '~/events/rpc/routes/plugin/utils'
import { T } from '~/i18n'
import clipboardPoll from '~/utils/clipboardPoll'
import { setTrayToolTip } from '~/utils/common'
@@ -34,6 +36,7 @@ import { IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import pkg from 'root/package.json'
import { openMainWindow } from '~/utils/windowHelper'
interface GuiMenuItem {
label: string
@@ -44,18 +47,10 @@ const buildMiniPageMenu = () => {
const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
const ClipboardWatcher = clipboardPoll
const submenu = buildPicBedListMenu()
const template = [
const template: Array<(MenuItemConstructorOptions) | (MenuItem)> = [
{
label: T('OPEN_MAIN_WINDOW'),
click () {
windowManager.get(IWindowList.SETTING_WINDOW)!.show()
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
if (autoCloseMiniWindow) {
if (windowManager.has(IWindowList.MINI_WINDOW)) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
}
click: openMainWindow
},
{
label: T('CHOOSE_DEFAULT_PICBED'),
@@ -69,7 +64,7 @@ const buildMiniPageMenu = () => {
}
},
{
label: T('HIDE_WINDOW'),
label: T('HIDE_MINI_WINDOW'),
click () {
BrowserWindow.getFocusedWindow()!.hide()
}
@@ -85,7 +80,7 @@ const buildMiniPageMenu = () => {
})
buildMiniPageMenu()
},
enabled: !isListeningClipboard
visible: !isListeningClipboard
},
{
label: T('STOP_WATCH_CLIPBOARD'),
@@ -95,7 +90,7 @@ const buildMiniPageMenu = () => {
ClipboardWatcher.removeAllListeners()
buildMiniPageMenu()
},
enabled: isListeningClipboard
visible: isListeningClipboard
},
{
label: T('RELOAD_APP'),
@@ -109,7 +104,6 @@ const buildMiniPageMenu = () => {
label: T('QUIT')
}
]
// @ts-ignore
return Menu.buildFromTemplate(template)
}
@@ -269,14 +263,14 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
picgoCoreIPC.handlePluginUninstall(plugin.fullName)
handlePluginUninstall(plugin.fullName)
}
}, {
label: T('UPDATE_PLUGIN'),
click () {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send(PICGO_HANDLE_PLUGIN_ING, plugin.fullName)
picgoCoreIPC.handlePluginUpdate(plugin.fullName)
handlePluginUpdate(plugin.fullName)
}
}]
for (const i in plugin.config) {
@@ -330,7 +324,6 @@ const buildPluginPageMenu = (plugin: IPicGoPlugin) => {
menu.push({
label: i.label,
click () {
// ipcRenderer.send('pluginActions', plugin.fullName, i.label)
const picgPlugin = picgo.pluginLoader.getPlugin(plugin.fullName)
if (picgPlugin?.guiMenu?.(picgo)?.length) {
const menu: GuiMenuItem[] = picgPlugin.guiMenu(picgo)

View File

@@ -1,45 +1,62 @@
import { ipcMain, IpcMainEvent } from 'electron'
import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from 'electron'
import { configRouter } from '~/events/rpc/routes/config'
import { toolboxRouter } from '~/events/rpc/routes/toolbox'
import logger from '@core/picgo/logger'
import { galleryRouter } from '~/events/rpc/routes/gallery'
import { picbedRouter } from '~/events/rpc/routes/picbed'
import { pluginRouter } from '~/events/rpc/routes/plugin'
import { settingRouter } from '~/events/rpc/routes/setting'
import { systemRouter } from '~/events/rpc/routes/system'
import { toolboxRouter } from '~/events/rpc/routes/toolbox'
import { trayRouter } from '~/events/rpc/routes/tray'
import { uploadRouter } from '~/events/rpc/routes/upload'
import { IRPCActionType } from '#/types/enum'
import { RPC_ACTIONS } from '#/events/constants'
import { IRPCActionType, IRPCType } from '#/types/enum'
import { RPC_ACTIONS, RPC_ACTIONS_INVOKE } from '#/events/constants'
const isDevelopment = process.env.NODE_ENV !== 'production'
class RPCServer implements IRPCServer {
private routes: IRPCRoutes = new Map()
private routesWithResponse: IRPCRoutes = new Map()
private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[], callbackId: string) => {
private rpcEventHandler = async (event: IpcMainEvent, action: IRPCActionType, args: any[]) => {
try {
const handler = this.routes.get(action)
if (!handler) {
return this.sendBack(event, action, null, callbackId)
if (isDevelopment) {
console.log(`action: ${action} args: ${JSON.stringify(args)}`)
}
const res = await handler?.(args, event)
this.sendBack(event, action, res, callbackId)
} catch (e) {
this.sendBack(event, action, null, callbackId)
const route = this.routes.get(action)
await route?.handler?.(event, args)
} catch (e: any) {
logger.error(e)
}
}
/**
* if sendback data is null, then it means that the action is not supported or error occurs
* if there is no callbackId, then do not send back
*/
private sendBack (event: IpcMainEvent, action: IRPCActionType, data: any, callbackId: string) {
if (callbackId) {
event.sender.send(RPC_ACTIONS, data, action, callbackId)
private rpcEventHandlerWithResponse = async (event: IpcMainInvokeEvent, action: IRPCActionType, args: any[]) => {
try {
if (isDevelopment) {
console.log(`action: ${action} args: ${JSON.stringify(args)}`)
}
const route = this.routesWithResponse.get(action)
return await route?.handler?.(event, args)
} catch (e: any) {
logger.error(e)
return undefined
}
}
start () {
ipcMain.on(RPC_ACTIONS, this.rpcEventHandler)
ipcMain.handle(RPC_ACTIONS_INVOKE, this.rpcEventHandlerWithResponse)
}
use (routes: IRPCRoutes) {
for (const [action, handler] of routes) {
this.routes.set(action, handler)
for (const [action, route] of routes) {
if (route.type === IRPCType.SEND) {
this.routes.set(action, route)
} else {
this.routesWithResponse.set(action, route)
}
}
}
@@ -50,9 +67,20 @@ class RPCServer implements IRPCServer {
const rpcServer = new RPCServer()
rpcServer.use(configRouter.routes())
rpcServer.use(toolboxRouter.routes())
rpcServer.use(systemRouter.routes())
const routes = [
galleryRouter.routes(),
picbedRouter.routes(),
pluginRouter.routes(),
settingRouter.routes(),
systemRouter.routes(),
toolboxRouter.routes(),
trayRouter.routes(),
uploadRouter.routes()
]
for (const route of routes) {
rpcServer.use(route)
}
export {
rpcServer

View File

@@ -1,9 +1,22 @@
import { IRPCActionType } from '#/types/enum'
import { IRPCType, IRPCActionType } from '#/types/enum'
interface IBatchAddParams {
action: IRPCActionType
handler: IRPCHandler<any>
type?: IRPCType
}
export class RPCRouter implements IRPCRouter {
private routeMap: IRPCRoutes = new Map()
add = <T>(action: IRPCActionType, handler: IRPCHandler<T>) => {
this.routeMap.set(action, handler)
add = <T>(action: IRPCActionType, handler: IRPCHandler<T>, type: IRPCType = IRPCType.SEND): this => {
this.routeMap.set(action, { handler, type })
return this
}
addBatch = (params: IBatchAddParams[]): this => {
for (const { action, handler, type = IRPCType.SEND } of params) {
this.routeMap.set(action, { handler, type })
}
return this
}

View File

@@ -1,42 +0,0 @@
import { RPCRouter } from '~/events/rpc/router'
import {
deleteUploaderConfig,
getUploaderConfigList,
resetUploaderConfig,
selectUploaderConfig,
updateUploaderConfig
} from '~/utils/handleUploaderConfig'
import { IRPCActionType } from '#/types/enum'
const configRouter = new RPCRouter()
configRouter
.add(IRPCActionType.GET_PICBED_CONFIG_LIST, async (args) => {
const [type] = args as IGetUploaderConfigListArgs
const config = getUploaderConfigList(type)
return config
})
.add(IRPCActionType.DELETE_PICBED_CONFIG, async (args) => {
const [type, id] = args as IDeleteUploaderConfigArgs
const config = deleteUploaderConfig(type, id)
return config
})
.add(IRPCActionType.SELECT_UPLOADER, async (args) => {
const [type, id] = args as ISelectUploaderConfigArgs
selectUploaderConfig(type, id)
return true
})
.add(IRPCActionType.UPDATE_UPLOADER_CONFIG, async (args) => {
const [type, id, config] = args as IUpdateUploaderConfigArgs
updateUploaderConfig(type, id, config)
return true
})
.add(IRPCActionType.RESET_UPLOADER_CONFIG, async (args) => {
const [type, id] = args as IUpdateUploaderConfigArgs
resetUploaderConfig(type, id)
return true
})
export {
configRouter
}

View File

@@ -0,0 +1,133 @@
import { clipboard } from 'electron'
import { GalleryDB } from '@core/datastore'
import picgo from '@core/picgo'
import logger from '@core/picgo/logger'
import { IFilter, IObject } from '@picgo/store/dist/types'
import GuiApi from 'apis/gui'
import { RPCRouter } from '~/events/rpc/router'
import { removeFileFromDogeInMain, removeFileFromHuaweiInMain, removeFileFromS3InMain, removeFileFromSFTPInMain } from '~/utils/deleteFunc'
import pasteTemplate from '~/utils/pasteTemplate'
import { ICOREBuildInEvent, IPasteStyle, IRPCActionType, IRPCType } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
const galleryRouter = new RPCRouter()
const galleryRoutes = [
{
action: IRPCActionType.GALLERY_PASTE_TEXT,
handler: async (_: IIPCEvent, args: [ item: ImgInfo, copy?: boolean]) => {
const [item, copy = true] = args
const pasteStyle = picgo.getConfig<IPasteStyle>(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
const customLink = picgo.getConfig<string>(configPaths.settings.customLink)
const txt = await pasteTemplate(pasteStyle, item, customLink)
if (copy) {
clipboard.writeText(txt)
}
return txt
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_REMOVE_FILES,
handler: async (_: IIPCEvent, args: [files: ImgInfo[]]) => {
setTimeout(() => {
picgo.emit(ICOREBuildInEvent.REMOVE, args[0], GuiApi.getInstance())
}, 500)
}
},
{
action: IRPCActionType.GALLERY_GET_DB,
handler: async (_: IIPCEvent, args: [filter: IFilter]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.get(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_GET_BY_ID_DB,
handler: async (_: IIPCEvent, args: [id: string]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.getById(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_UPDATE_BY_ID_DB,
handler: async (_: IIPCEvent, args: [id: string, value: IObject]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.updateById(args[0], args[1])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_REMOVE_BY_ID_DB,
handler: async (_: IIPCEvent, args: [id: string]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.removeById(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_INSERT_DB,
handler: async (_: IIPCEvent, args: [value: IObject]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.insert(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_INSERT_DB_BATCH,
handler: async (_: IIPCEvent, args: [value: IObject[]]) => {
const dbStore = GalleryDB.getInstance()
return await dbStore.insertMany(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_LOG_DELETE_MSG,
handler: async (_: IIPCEvent, args: [msg: string, logLevel: ILogType]) => {
const [msg, logLevel] = args
console.log(msg, logLevel)
logger[logLevel](msg)
}
},
{
action: IRPCActionType.GALLERY_DELETE_SFTP_FILE,
handler: async (_: IIPCEvent, args: [config: ISftpPlistConfig, fileName: string]) => {
const [config, fileName] = args
return await removeFileFromSFTPInMain(config, fileName)
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_DELETE_AWS_S3_FILE,
handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
return await removeFileFromS3InMain(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_DELETE_DOGE_FILE,
handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
return await removeFileFromDogeInMain(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE,
handler: async (_: IIPCEvent, args: [configMap: IStringKeyMap]) => {
return await removeFileFromHuaweiInMain(args[0])
},
type: IRPCType.INVOKE
}
]
galleryRouter.addBatch(galleryRoutes)
export {
galleryRouter
}

View File

@@ -0,0 +1,99 @@
import picgo from '@core/picgo'
import { RPCRouter } from '~/events/rpc/router'
import {
deleteUploaderConfig,
getUploaderConfigList,
resetUploaderConfig,
selectUploaderConfig,
updateUploaderConfig
} from '~/utils/handleUploaderConfig'
import { IRPCActionType, IRPCType } from '#/types/enum'
const picbedRouter = new RPCRouter()
const handleConfigWithFunction = (config: any[]) => {
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()
}
}
return config
}
const picbedRoutes = [
{
action: IRPCActionType.PICBED_GET_CONFIG_LIST,
handler: async (_: IIPCEvent, args: [type: string]) => {
const config = getUploaderConfigList(args[0])
return config
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.PICBED_DELETE_CONFIG,
handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
const [type, id] = args
const config = deleteUploaderConfig(type, id)
return config
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.UPLOADER_SELECT,
handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
const [type, id] = args
selectUploaderConfig(type, id)
return true
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.UPLOADER_UPDATE_CONFIG,
handler: async (_: IIPCEvent, args: [type: string, id: string, config: IStringKeyMap]) => {
const [type, id, config] = args
updateUploaderConfig(type, id, config)
return true
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.UPLOADER_RESET_CONFIG,
handler: async (_: IIPCEvent, args: [type: string, id: string]) => {
const [type, id] = args
resetUploaderConfig(type, id)
return true
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.PICBED_GET_PICBED_CONFIG,
handler: async (_: IIPCEvent, args: [type: string]) => {
const type = args[0]
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
}
}
},
type: IRPCType.INVOKE
}
]
picbedRouter.addBatch(picbedRoutes)
export {
picbedRouter
}

View File

@@ -0,0 +1,37 @@
import { RPCRouter } from '~/events/rpc/router'
import {
pluginImportLocalFunc,
pluginInstallFunc,
pluginGetListFunc,
pluginUpdateAllFunc
} from '~/events/rpc/routes/plugin/utils'
import { IRPCActionType } from '#/types/enum'
const pluginRouter = new RPCRouter()
const pluginRoutes = [
{
action: IRPCActionType.PLUGIN_GET_LIST,
handler: pluginGetListFunc
},
{
action: IRPCActionType.PLUGIN_INSTALL,
handler: pluginInstallFunc
},
{
action: IRPCActionType.PLUGIN_IMPORT_LOCAL,
handler: pluginImportLocalFunc
},
{
action: IRPCActionType.PLUGIN_UPDATE_ALL,
handler: pluginUpdateAllFunc
}
]
pluginRouter.addBatch(pluginRoutes)
export {
pluginRouter
}

View File

@@ -0,0 +1,227 @@
import { dialog, shell } from 'electron'
import { IGuiMenuItem, PicGo as PicGoCore } from 'piclist'
import path from 'path'
import { dbPathDir } from '@core/datastore/dbChecker'
import picgo from '@core/picgo'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import windowManager from 'apis/app/window/windowManager'
import { T } from '~/i18n'
import { showNotification } from '~/utils/common'
import { handleStreamlinePluginName, simpleClone } from '#/utils/common'
import { ICOREBuildInEvent, IPicGoHelperType, IWindowList } from '#/types/enum'
const STORE_PATH = dbPathDir()
// eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
// get uploader or transformer config
const getConfig = (name: string, type: IPicGoHelperType, ctx: PicGoCore) => {
let config: any[] = []
if (name === '') {
return config
} else {
const handler = ctx.helper[type].get(name)
if (handler) {
if (handler.config) {
config = handler.config(ctx)
}
}
return config
}
}
const handleConfigWithFunction = (config: any[]) => {
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()
}
}
return config
}
const getPluginList = (): IPicGoPlugin[] => {
const pluginList = picgo.pluginLoader.getFullList()
const list = []
for (const i in pluginList) {
const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
const uploaderName = plugin.uploader || ''
const transformerName = plugin.transformer || ''
let menu: Omit<IGuiMenuItem, 'handle'>[] = []
if (plugin.guiMenu) {
menu = plugin.guiMenu(picgo).map(item => ({
label: item.label
}))
}
let gui = false
if (pluginPKG.keywords && pluginPKG.keywords.length > 0) {
if (pluginPKG.keywords.includes('picgo-gui-plugin')) {
gui = true
}
}
const obj: IPicGoPlugin = {
name: handleStreamlinePluginName(pluginList[i]),
fullName: pluginList[i],
author: pluginPKG.author.name || pluginPKG.author,
description: pluginPKG.description,
logo: 'file://' + path.join(pluginPath, 'logo.png').split(path.sep).join('/'),
version: pluginPKG.version,
gui,
config: {
plugin: {
fullName: pluginList[i],
name: handleStreamlinePluginName(pluginList[i]),
config: plugin.config ? handleConfigWithFunction(plugin.config(picgo)) : []
},
uploader: {
name: uploaderName,
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.uploader, picgo))
},
transformer: {
name: transformerName,
config: handleConfigWithFunction(getConfig(uploaderName, IPicGoHelperType.transformer, picgo))
}
},
enabled: picgo.getConfig(`picgoPlugins.${pluginList[i]}`),
homepage: pluginPKG.homepage ? pluginPKG.homepage : '',
guiMenu: menu,
ing: false
}
list.push(obj)
}
return list
}
const handleNPMError = (): IDispose => {
const handler = (msg: string) => {
if (msg === 'NPM is not installed') {
dialog.showMessageBox({
title: T('TIPS_ERROR'),
message: T('TIPS_INSTALL_NODE_AND_RELOAD_PICGO'),
buttons: ['Yes']
}).then((res) => {
if (res.response === 0) {
shell.openExternal('https://nodejs.org/')
}
})
}
}
picgo.once(ICOREBuildInEvent.FAILED, handler)
return () => picgo.off(ICOREBuildInEvent.FAILED, handler)
}
export const handlePluginUpdate = async (fullName: string | string[]) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const dispose = handleNPMError()
const res = await picgo.pluginHandler.update(typeof fullName === 'string' ? [fullName] : fullName)
if (res.success) {
window.webContents.send('updateSuccess', res.body[0])
} else {
showNotification({
title: T('PLUGIN_UPDATE_FAILED'),
body: res.body as string
})
}
window.webContents.send('hideLoading')
dispose()
}
export const handlePluginUninstall = async (fullName: string) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const dispose = handleNPMError()
const res = await picgo.pluginHandler.uninstall([fullName])
if (res.success) {
window.webContents.send('uninstallSuccess', res.body[0])
shortKeyHandler.unregisterPluginShortKey(res.body[0])
} else {
showNotification({
title: T('PLUGIN_UNINSTALL_FAILED'),
body: res.body as string
})
}
window.webContents.send('hideLoading')
dispose()
}
export const pluginGetListFunc = async (event: IIPCEvent) => {
try {
const list = simpleClone(getPluginList())
// here can just send JS Object not function
// or will cause [Failed to serialize arguments] error
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
picgo.log.error(e)
}
}
export const pluginInstallFunc = async (event: IIPCEvent, args: [fullName: string]) => {
const fullName = args[0]
const dispose = handleNPMError()
const res = await picgo.pluginHandler.install([fullName])
event.sender.send('installPlugin', {
success: res.success,
body: fullName,
errMsg: res.success ? '' : res.body
})
if (res.success) {
shortKeyHandler.registerPluginShortKey(res.body[0])
} else {
showNotification({
title: T('PLUGIN_INSTALL_FAILED'),
body: res.body as string
})
}
event.sender.send('hideLoading')
dispose()
}
export const pluginImportLocalFunc = async (event: IIPCEvent) => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
const res = await dialog.showOpenDialog(settingWindow, {
properties: ['openDirectory']
})
const filePaths = res.filePaths
if (filePaths.length > 0) {
const res = await picgo.pluginHandler.install(filePaths)
if (res.success) {
try {
const list = simpleClone(getPluginList())
event.sender.send('pluginList', list)
} catch (e: any) {
event.sender.send('pluginList', [])
showNotification({
title: T('TIPS_GET_PLUGIN_LIST_FAILED'),
body: e.message
})
}
showNotification({
title: T('PLUGIN_IMPORT_SUCCEED'),
body: ''
})
} else {
showNotification({
title: T('PLUGIN_IMPORT_FAILED'),
body: res.body as string
})
}
}
event.sender.send('hideLoading')
}
export const pluginUpdateAllFunc = async (_: IIPCEvent, args: [list: string[]]) => {
handlePluginUpdate(args[0])
}

View File

@@ -0,0 +1,25 @@
import { IRPCActionType } from '#/types/enum'
import server from '~/server'
import webServer from '~/server/webServer'
export default [
{
action: IRPCActionType.ADVANCED_UPDATE_SERVER,
handler: async () => {
server.restart()
}
},
{
action: IRPCActionType.ADVANCED_STOP_WEB_SERVER,
handler: async () => {
webServer.stop()
}
},
{
action: IRPCActionType.ADVANCED_RESTART_WEB_SERVER,
handler: async () => {
webServer.restart()
}
}
]

View File

@@ -0,0 +1,82 @@
import { app } from 'electron'
import fs from 'fs-extra'
import path from 'path'
import logger from '@core/picgo/logger'
import { downloadFile, uploadFile } from '~/utils/syncSettings'
import { IRPCActionType, IRPCType } from '#/types/enum'
const STORE_PATH = app.getPath('userData')
const commonConfigList = ['data.json', 'data.bak.json']
const manageConfigList = ['manage.json', 'manage.bak.json']
export default [
{
action: IRPCActionType.CONFIGURE_MIGRATE_FROM_PICGO,
handler: async () => {
const picGoConfigPath = STORE_PATH.replace('piclist', 'picgo')
const files = [
'data.json',
'data.bak.json',
'picgo.db',
'picgo.bak.db'
]
try {
await Promise.all(files.map(async file => {
const sourcePath = path.join(picGoConfigPath, file)
const targetPath = path.join(STORE_PATH, file.replace('picgo', 'piclist'))
await fs.copy(sourcePath, targetPath, { overwrite: true })
}
))
return true
} catch (err: any) {
logger.error(err)
throw new Error('Migrate failed')
}
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_UPLOAD_COMMON_CONFIG,
handler: async () => {
return await uploadFile(commonConfigList)
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_UPLOAD_MANAGE_CONFIG,
handler: async () => {
return await uploadFile(manageConfigList)
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_UPLOAD_ALL_CONFIG,
handler: async () => {
return await uploadFile([...commonConfigList, ...manageConfigList])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_DOWNLOAD_COMMON_CONFIG,
handler: async () => {
return await downloadFile(commonConfigList)
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_DOWNLOAD_MANAGE_CONFIG,
handler: async () => {
return await downloadFile(manageConfigList)
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.CONFIGURE_DOWNLOAD_ALL_CONFIG,
handler: async () => {
return await downloadFile([...commonConfigList, ...manageConfigList])
},
type: IRPCType.INVOKE
}
]

View File

@@ -0,0 +1,21 @@
import { RPCRouter } from '~/events/rpc/router'
import advancedRoutes from '~/events/rpc/routes/setting/advanced'
import configureRoutes from '~/events/rpc/routes/setting/configure'
import mainAppRoutes from '~/events/rpc/routes/setting/mainApp'
import shortKeyRoutes from '~/events/rpc/routes/setting/shortKey'
const settingRouter = new RPCRouter()
const settingRoutes = [
...advancedRoutes,
...configureRoutes,
...mainAppRoutes,
...shortKeyRoutes
]
settingRouter.addBatch(settingRoutes)
export {
settingRouter
}

View File

@@ -0,0 +1,65 @@
import { app, IpcMainEvent, shell } from 'electron'
import fs from 'fs-extra'
import path from 'path'
import picgo from '@core/picgo'
import { dbPathDir } from '@core/datastore/dbChecker'
import { IRPCActionType, IRPCType } from '#/types/enum'
const STORE_PATH = dbPathDir()
export default [
{
action: IRPCActionType.PICLIST_GET_CONFIG,
handler: async (_: IIPCEvent, args: [key?: string]) => {
return picgo.getConfig(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.PICLIST_GET_CONFIG_SYNC,
handler: async (event: IIPCEvent, args: [key?: string]) => {
const result = picgo.getConfig(args[0])
const eventInstance = event as IpcMainEvent
eventInstance.returnValue = result
}
},
{
action: IRPCActionType.PICLIST_SAVE_CONFIG,
handler: async (_: IIPCEvent, args: [data: IObj]) => {
picgo.saveConfig(args[0])
}
},
{
action: IRPCActionType.PICLIST_OPEN_FILE,
handler: async (_: IIPCEvent, args: [fileName: string]) => {
const abFilePath = path.join(STORE_PATH, args[0])
if (!fs.existsSync(abFilePath)) {
fs.writeFileSync(abFilePath, '')
}
shell.openPath(abFilePath)
}
},
{
action: IRPCActionType.PICLIST_OPEN_DIRECTORY,
handler: async (_: IIPCEvent, args: [dirPath?: string, inStorePath?: boolean]) => {
let [dirPath, inStorePath = true] = args
if (inStorePath) {
dirPath = path.join(STORE_PATH, dirPath || '')
}
if (!dirPath || !fs.existsSync(dirPath)) {
return
}
shell.openPath(dirPath)
}
},
{
action: IRPCActionType.PICLIST_AUTO_START,
handler: async (_: IIPCEvent, args: [val: boolean]) => {
app.setLoginItemSettings({
openAtLogin: args[0]
})
}
}
]

View File

@@ -0,0 +1,46 @@
import {
Notification
} from 'electron'
import bus from '@core/bus'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import { T } from '~/i18n'
import { IRPCActionType, IRPCType } from '#/types/enum'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
const notificationFunc = (result: boolean) => {
const notification = new Notification({
title: T(`OPERATION_${result ? 'SUCCEED' : 'FAILED'}`),
body: T(`TIPS_SHORTCUT_MODIFIED_${result ? 'SUCCEED' : 'CONFLICT'}`)
})
notification.show()
}
export default [
{
action: IRPCActionType.SHORTKEY_UPDATE,
handler: async (_: IIPCEvent, args: [item: IShortKeyConfig, oldKey: string, from: string]) => {
const [item, oldKey, from] = args
const result = shortKeyHandler.updateShortKey(item, oldKey, from)
notificationFunc(result)
return result
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.SHORTKEY_BIND_OR_UNBIND,
handler: async (_: IIPCEvent, args: [item: IShortKeyConfig, from: string]) => {
const [item, from] = args
const result = shortKeyHandler.bindOrUnbindShortKey(item, from)
notificationFunc(result)
}
},
{
action: IRPCActionType.SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE,
handler: async (_: IIPCEvent, args: [status: boolean]) => {
const [status] = args
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, status)
}
}
]

View File

@@ -1,24 +0,0 @@
import { app, clipboard, shell } from 'electron'
import { RPCRouter } from '~/events/rpc/router'
import { IRPCActionType } from '#/types/enum'
const systemRouter = new RPCRouter()
systemRouter
.add(IRPCActionType.RELOAD_APP, async () => {
app.relaunch()
app.exit(0)
})
.add(IRPCActionType.OPEN_FILE, async (args) => {
const [filePath] = args as IOpenFileArgs
shell.openPath(filePath)
})
.add(IRPCActionType.COPY_TEXT, async (args) => {
const [text] = args as ICopyTextArgs
return clipboard.writeText(text)
})
export {
systemRouter
}

View File

@@ -0,0 +1,62 @@
import { app, shell } from 'electron'
import picgo from '@core/picgo'
import windowManager from 'apis/app/window/windowManager'
import { i18nManager } from '~/i18n'
import { IRPCActionType, IWindowList } from '#/types/enum'
import { GET_CURRENT_LANGUAGE, GET_LANGUAGE_LIST, SET_CURRENT_LANGUAGE } from '#/events/constants'
export default [
{
action: IRPCActionType.RELOAD_APP,
handler: async () => {
app.relaunch()
app.exit(0)
}
},
{
action: IRPCActionType.OPEN_FILE,
handler: async (_: IIPCEvent, args: [filePath: string]) => {
shell.openPath(args[0])
}
},
{
action: IRPCActionType.OPEN_URL,
handler: async (_: IIPCEvent, args: [url: string]) => {
shell.openExternal(args[0])
}
},
{
action: IRPCActionType.GET_LANGUAGE_LIST,
handler: async (event: IIPCEvent) => {
event.sender.send(GET_LANGUAGE_LIST, i18nManager.languageList)
}
},
{
action: IRPCActionType.GET_CURRENT_LANGUAGE,
handler: async (event: IIPCEvent) => {
const { lang, locales } = i18nManager.getCurrentLocales()
event.sender.send(GET_CURRENT_LANGUAGE, lang, locales)
}
},
{
action: IRPCActionType.SET_CURRENT_LANGUAGE,
handler: async (_: IIPCEvent, args: [language: string]) => {
i18nManager.setCurrentLanguage(args[0])
const { lang, locales } = i18nManager.getCurrentLocales()
picgo.i18n.setLanguage(lang)
if (process.platform === 'darwin') {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)
trayWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
}
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
settingWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
if (windowManager.has(IWindowList.MINI_WINDOW)) {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)
miniWindow?.webContents.send(SET_CURRENT_LANGUAGE, lang, locales)
}
}
}
]

View File

@@ -0,0 +1,16 @@
import { RPCRouter } from '~/events/rpc/router'
import appRoutes from '~/events/rpc/routes/system/app'
import windowRoutes from '~/events/rpc/routes/system/window'
const systemRouter = new RPCRouter()
const systemRoutes = [
...appRoutes,
...windowRoutes
]
systemRouter.addBatch(systemRoutes)
export {
systemRouter
}

View File

@@ -0,0 +1,137 @@
import { app, BrowserWindow } from 'electron'
import windowManager from 'apis/app/window/windowManager'
import {
buildMainPageMenu,
buildMiniPageMenu,
buildPicBedListMenu,
buildPluginPageMenu
} from '~/events/remotes/menu'
import { openMiniWindow } from '~/utils/windowHelper'
import { IRPCActionType, IWindowList } from '#/types/enum'
export default [
{
action: IRPCActionType.HIDE_DOCK,
handler: async (_: IIPCEvent, args: [value: boolean]) => {
args[0] ? app.dock.hide() : app.dock.show()
}
},
{
action: IRPCActionType.OPEN_WINDOW,
handler: async (_: IIPCEvent, args: [windowName: IWindowList]) => {
const window = windowManager.get(args[0])
if (window) {
window.show()
}
}
},
{
action: IRPCActionType.OPEN_MANUAL_WINDOW,
handler: async () => {
windowManager.get(IWindowList.MANUAL_WINDOW)!.show()
}
},
{
action: IRPCActionType.OPEN_MINI_WINDOW,
handler: async () => {
openMiniWindow()
}
},
{
action: IRPCActionType.CLOSE_WINDOW,
handler: async () => {
const window = BrowserWindow.getFocusedWindow()
if (process.platform === 'linux') {
window?.hide()
} else {
window?.close()
}
}
},
{
action: IRPCActionType.MINIMIZE_WINDOW,
handler: async () => {
const window = BrowserWindow.getFocusedWindow()
window?.minimize()
}
},
{
action: IRPCActionType.SHOW_MINI_PAGE_MENU,
handler: async () => {
const window = windowManager.get(IWindowList.MINI_WINDOW)!
const menu = buildMiniPageMenu()
menu.popup({
window
})
}
},
{
action: IRPCActionType.SHOW_MAIN_PAGE_MENU,
handler: async () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildMainPageMenu(window)
menu.popup({
window
})
}
},
{
action: IRPCActionType.SHOW_UPLOAD_PAGE_MENU,
handler: async () => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildPicBedListMenu()
menu.popup({
window
})
}
},
{
action: IRPCActionType.SHOW_PLUGIN_PAGE_MENU,
handler: async (_: IIPCEvent, args: [plugin: IPicGoPlugin]) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
const menu = buildPluginPageMenu(args[0])
menu.popup({
window
})
}
},
{
action: IRPCActionType.SET_MINI_WINDOW_POS,
handler: async (_: IIPCEvent, args: [pos: IMiniWindowPos]) => {
const window = BrowserWindow.getFocusedWindow()
window?.setBounds(args[0])
}
},
{
action: IRPCActionType.MINI_WINDOW_ON_TOP,
handler: async (_: IIPCEvent, args: [isOnTop: boolean]) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.setAlwaysOnTop(args[0])
}
},
{
action: IRPCActionType.MAIN_WINDOW_ON_TOP,
handler: async () => {
const mainWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
const isAlwaysOnTop = mainWindow.isAlwaysOnTop()
mainWindow.setAlwaysOnTop(!isAlwaysOnTop)
}
},
{
action: IRPCActionType.UPDATE_MINI_WINDOW_ICON,
handler: async (_: IIPCEvent, args: [iconPath: string]) => {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.webContents.send('updateMiniIcon', args[0])
}
},
{
action: IRPCActionType.REFRESH_SETTING_WINDOW,
handler: async () => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.webContents.reloadIgnoringCache()
}
}
]

View File

@@ -11,7 +11,7 @@ import { T } from '~/i18n'
import { IToolboxItemCheckStatus, IToolboxItemType } from '#/types/enum'
const getProxy = (proxyStr: string): AxiosRequestConfig['proxy'] | false => {
function getProxy (proxyStr: string): AxiosRequestConfig['proxy'] | null {
if (proxyStr) {
try {
const proxyOptions = new URL(proxyStr)
@@ -20,10 +20,9 @@ const getProxy = (proxyStr: string): AxiosRequestConfig['proxy'] | false => {
port: parseInt(proxyOptions.port || '0', 10),
protocol: proxyOptions.protocol
}
} catch (e) {
}
} catch (e) {}
}
return false
return null
}
const sendToolboxRes = sendToolboxResWithType(IToolboxItemType.HAS_PROBLEM_WITH_PROXY)

View File

@@ -3,7 +3,8 @@ import { checkFileMap, fixFileMap } from '~/events/rpc/routes/toolbox/checkFile'
import { checkProxyMap } from '~/events/rpc/routes/toolbox/checkProxy'
import { RPCRouter } from '~/events/rpc/router'
import { IRPCActionType, IToolboxItemType } from '#/types/enum'
import { IRPCActionType, IRPCType, IToolboxItemType } from '#/types/enum'
import { IpcMainEvent } from 'electron'
const toolboxRouter = new RPCRouter()
@@ -19,30 +20,37 @@ const toolboxFixMap: Partial<IToolboxFixMap<IToolboxItemType>> = {
}
toolboxRouter
.add(IRPCActionType.TOOLBOX_CHECK, async (args, event) => {
const [type] = args as IToolboxCheckArgs
if (type) {
const handler = toolboxCheckMap[type]
if (handler) {
handler(event)
}
} else {
// do check all
for (const key in toolboxCheckMap) {
const handler = toolboxCheckMap[key as IToolboxItemType]
.add(
IRPCActionType.TOOLBOX_CHECK,
async (event, args) => {
const [type] = args as IToolboxCheckArgs
if (type) {
const handler = toolboxCheckMap[type]
if (handler) {
handler(event)
handler(event as IpcMainEvent)
}
} else {
// do check all
for (const key in toolboxCheckMap) {
const handler = toolboxCheckMap[key as IToolboxItemType]
if (handler) {
handler(event as IpcMainEvent)
}
}
}
}
})
.add(IRPCActionType.TOOLBOX_CHECK_FIX, async (args, event) => {
const [type] = args as IToolboxCheckArgs
const handler = toolboxFixMap[type]
if (handler) {
return await handler(event)
}
})
},
IRPCType.SEND
)
.add(
IRPCActionType.TOOLBOX_CHECK_FIX, async (event, args) => {
const [type] = args as IToolboxCheckArgs
const handler = toolboxFixMap[type]
if (handler) {
return await handler(event as IpcMainEvent)
}
},
IRPCType.INVOKE
)
export {
toolboxRouter

View File

@@ -1,9 +1,11 @@
import { IpcMainEvent } from 'electron'
import { IRPCActionType, IToolboxItemType } from '#/types/enum'
export const sendToolboxResWithType = (type: IToolboxItemType) => (event: IpcMainEvent, res?: Omit<IToolboxCheckRes, 'type'>) => {
return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
...res,
type
})
export function sendToolboxResWithType (type: IToolboxItemType) {
return (event: IpcMainEvent, res?: Omit<IToolboxCheckRes, 'type'>) => {
return event.sender.send(IRPCActionType.TOOLBOX_CHECK_RES, {
...res,
type
})
}
}

View File

@@ -0,0 +1,71 @@
import {
Notification
} from 'electron'
import { RPCRouter } from '~/events/rpc/router'
import { generateShortUrl, setTrayToolTip, handleCopyUrl } from '~/utils/common'
import { IRPCActionType, IRPCType, IPasteStyle, IWindowList } from '#/types/enum'
import db, { GalleryDB } from '@core/datastore'
import uploader from 'apis/app/uploader'
import windowManager from 'apis/app/window/windowManager'
import { T } from '~/i18n'
import pasteTemplate from '~/utils/pasteTemplate'
import { configPaths } from '#/utils/configPaths'
const trayRouter = new RPCRouter()
const trayRoutes = [
{
action: IRPCActionType.TRAY_SET_TOOL_TIP,
handler: async (_: IIPCEvent, args: [text: string]) => {
setTrayToolTip(args[0])
}
},
{
action: IRPCActionType.TRAY_GET_SHORT_URL,
handler: async (_: IIPCEvent, args: [url: string]) => {
return await generateShortUrl(args[0])
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.TRAY_UPLOAD_CLIPBOARD_FILES,
handler: async () => {
const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
// macOS use builtin clipboard is OK
const img = await uploader.setWebContents(trayWindow.webContents).uploadWithBuildInClipboard()
if (img !== false) {
const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
handleCopyUrl(await (pasteTemplate(pasteStyle, img[0], db.get(configPaths.settings.customLink))))
const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
if (isShowResultNotification) {
const notification = new Notification({
title: T('UPLOAD_SUCCEED'),
body: img[0].imgUrl!
// icon: file[0]
// icon: img[0].imgUrl
})
notification.show()
}
await GalleryDB.getInstance().insert(img[0])
trayWindow.webContents.send('clipboardFiles', [])
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents.send('updateGallery')
}
}
trayWindow.webContents.send('uploadFiles')
}
}
]
trayRouter.addBatch(trayRoutes)
export {
trayRouter
}

View File

@@ -0,0 +1,35 @@
import { RPCRouter } from '~/events/rpc/router'
import getPicBeds from '~/utils/getPicBeds'
import { uploadChoosedFiles, uploadClipboardFiles } from '~/apis/app/uploader/apis'
import { IRPCActionType, IRPCType } from '#/types/enum'
const uploadRouter = new RPCRouter()
const uploadRoutes = [
{
action: IRPCActionType.MAIN_GET_PICBED,
handler: async () => {
return getPicBeds()
},
type: IRPCType.INVOKE
},
{
action: IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE,
handler: async () => {
uploadClipboardFiles()
}
},
{
action: IRPCActionType.UPLOAD_CHOOSED_FILES,
handler: async (evt: IIPCEvent, args: [files: IFileWithPath[]]) => {
return uploadChoosedFiles(evt.sender, args[0])
}
}
]
uploadRouter.addBatch(uploadRoutes)
export {
uploadRouter
}

View File

@@ -10,8 +10,10 @@ fs.ensureDirSync(imgFilePath)
const serverPort = 36699
let server: http.Server
export function startFileServer () {
const server = http.createServer((req, res) => {
server = http.createServer((req, res) => {
const requestPath = req.url?.split('?')[0]
const filePath = path.join(imgFilePath, decodeURIComponent(requestPath as string))
@@ -31,3 +33,9 @@ export function startFileServer () {
logger.error(err)
})
}
export function stopFileServer () {
server.close(() => {
logger.info('File server is stopped')
})
}

View File

@@ -32,8 +32,7 @@ import {
import windowManager from 'apis/app/window/windowManager'
import busEventList from '~/events/busEventList'
import ipcList from '~/events/ipcList'
import { startFileServer } from '~/fileServer'
import { startFileServer, stopFileServer } from '~/fileServer'
import { T } from '~/i18n'
import '~/lifeCycle/errorHandler'
import fixPath from '~/lifeCycle/fixPath'
@@ -52,6 +51,7 @@ import updateChecker from '~/utils/updateChecker'
import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { CLIPBOARD_IMAGE_FOLDER } from '#/utils/static'
import { rpcServer } from '~/events/rpc'
const isDevelopment = process.env.NODE_ENV !== 'production'
@@ -146,7 +146,7 @@ class LifeCycle {
fixPath()
beforeOpen()
initI18n()
ipcList.listen()
rpcServer.start()
getManageApi()
UpDownTaskQueue.getInstance()
manageIpcList.listen()
@@ -285,6 +285,8 @@ class LifeCycle {
globalShortcut.unregisterAll()
bus.removeAllListeners()
server.shutdown()
webServer.stop()
stopFileServer()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {

View File

@@ -1,5 +1,6 @@
import {
IpcMainEvent,
IpcMainInvokeEvent,
ipcMain
} from 'electron'
@@ -9,20 +10,19 @@ import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_R
const manageApi = getManageApi()
const handleManageGetConfig = () => {
ipcMain.on(PICLIST_MANAGE_GET_CONFIG, (event: IpcMainEvent, key: string | undefined, callbackId: string) => {
const result = manageApi.getConfig(key)
event.sender.send(PICLIST_MANAGE_GET_CONFIG, result, callbackId)
ipcMain.handle(PICLIST_MANAGE_GET_CONFIG, (_: IpcMainInvokeEvent, key: string | undefined) => {
return manageApi.getConfig(key)
})
}
const handleManageSaveConfig = () => {
ipcMain.on(PICLIST_MANAGE_SAVE_CONFIG, (_event: IpcMainEvent, data: any) => {
ipcMain.on(PICLIST_MANAGE_SAVE_CONFIG, (_: IpcMainEvent, data: any) => {
manageApi.saveConfig(data)
})
}
const handleManageRemoveConfig = () => {
ipcMain.on(PICLIST_MANAGE_REMOVE_CONFIG, (_event: IpcMainEvent, key: string, propName: string) => {
ipcMain.on(PICLIST_MANAGE_REMOVE_CONFIG, (_: IpcMainEvent, key: string, propName: string) => {
manageApi.removeConfig(key, propName)
})
}

View File

@@ -11,12 +11,13 @@ import logger from '@core/picgo/logger'
import { AESHelper } from '~/utils/aesHelper'
import { changeCurrentUploader } from '~/utils/handleUploaderConfig'
import { uploadChoosedFiles, uploadClipboardFiles, deleteChoosedFiles } from 'apis/app/uploader/apis'
import { uploadChoosedFiles, uploadClipboardFiles } from 'apis/app/uploader/apis'
import windowManager from 'apis/app/window/windowManager'
import { markdownContent } from '~/server/apiDoc'
import router from '~/server/router'
import {
deleteChoosedFiles,
handleResponse
} from '~/server/utils'

View File

@@ -1,4 +1,20 @@
import {
Notification
} from 'electron'
import picgo from '@core/picgo'
import logger from '@core/picgo/logger'
import db, { GalleryDB } from '@core/datastore'
import windowManager from 'apis/app/window/windowManager'
import GuiApi from '~/apis/gui'
import { T } from '~/i18n/index'
import { configPaths } from '#/utils/configPaths'
import { picBedsCanbeDeleted } from '#/utils/static'
import { ICOREBuildInEvent, IWindowList } from '#/types/enum'
import ALLApi from '@/apis/allApi'
export const handleResponse = ({
response,
@@ -31,3 +47,43 @@ export const ensureHTTPLink = (url: string): string => {
? url
: `http://${url}`
}
export const deleteChoosedFiles = async (list: ImgInfo[]): Promise<boolean[]> => {
const result = []
for (const item of list) {
if (item.id) {
try {
const dbStore = GalleryDB.getInstance()
const file = await dbStore.getById(item.id)
await dbStore.removeById(item.id)
if (await db.get(configPaths.settings.deleteCloudFile)) {
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
const noteFunc = (value: boolean) => {
const notification = new Notification({
title: T('MANAGE_BUCKET_BATCH_DELETE_ERROR_MSG_MSG2'),
body: T(value
? 'GALLERY_SYNC_DELETE_NOTICE_SUCCEED'
: 'GALLERY_SYNC_DELETE_NOTICE_FAILED'
)
})
notification.show()
}
setTimeout(() => {
ALLApi.delete(item).then(noteFunc)
}, 0)
}
}
setTimeout(() => {
picgo.emit(ICOREBuildInEvent.REMOVE, [file], GuiApi.getInstance())
}, 500)
result.push(true)
} catch (e) {
result.push(false)
}
}
}
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.get(IWindowList.SETTING_WINDOW)!.webContents?.send('updateGallery')
}
return result
}

View File

@@ -2,10 +2,13 @@ import axios from 'axios'
import crypto from 'crypto'
import http, { AgentOptions } from 'http'
import https from 'https'
import path from 'path'
import { ISftpPlistConfig } from 'piclist'
import querystring from 'querystring'
import { S3Client, DeleteObjectCommand, S3ClientConfig } from '@aws-sdk/client-s3'
import { NodeHttpHandler } from '@smithy/node-http-handler'
import SSHClient from '~/utils/sshClient'
import { getAgent } from '~/manage/utils/common'
interface DogecloudTokenFull {
@@ -219,3 +222,18 @@ export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
return false
}
}
export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
try {
const client = SSHClient.instance
await client.connect(config)
const uploadPath = `/${(config.uploadPath || '')}/`.replace(/\/+/g, '/')
const remote = path.join(uploadPath, fileName)
const deleteResult = await client.deleteFileSFTP(config, remote)
client.close()
return deleteResult
} catch (err: any) {
console.log(err)
return false
}
}

View File

@@ -0,0 +1,56 @@
import { screen } from 'electron'
import db from '@core/datastore'
import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
export function openMiniWindow (hideSettingWindow:boolean = true) {
const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
miniWindow.removeAllListeners()
if (db.get(configPaths.settings.miniWindowOntop)) {
miniWindow.setAlwaysOnTop(true)
}
const { width, height } = screen.getPrimaryDisplay().workAreaSize
const lastPosition = db.get(configPaths.settings.miniWindowPosition)
if (lastPosition) {
miniWindow.setPosition(lastPosition[0], lastPosition[1])
} else {
miniWindow.setPosition(width - 100, height - 100)
}
const setPositionFunc = () => {
const position = miniWindow.getPosition()
db.set(configPaths.settings.miniWindowPosition, position)
}
miniWindow.on('close', setPositionFunc)
miniWindow.on('move', setPositionFunc)
miniWindow.show()
miniWindow.focus()
if (hideSettingWindow) {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.hide()
} else {
const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
}
}
}
export const openMainWindow = () => {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
settingWindow!.show()
settingWindow!.focus()
if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}
export const hideMiniWindow = () => {
if (windowManager.has(IWindowList.MINI_WINDOW)) {
windowManager.get(IWindowList.MINI_WINDOW)!.hide()
}
}

View File

@@ -17,6 +17,7 @@ import { FORCE_UPDATE } from '#/events/constants'
useATagClick()
const store = useStore()
onBeforeMount(async () => {
const config = await getConfig<IConfig>()
if (config) {

View File

@@ -1,7 +1,7 @@
import axios from 'axios'
import path from 'path'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,6 +1,6 @@
import OSS from 'ali-oss'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,15 +1,15 @@
import { ipcRenderer } from 'electron'
import { deleteFailedLog, getRawData } from '@/utils/common'
import { getRawData, triggerRPC } from '@/utils/common'
import { removeFileFromS3InMain } from '~/utils/deleteFunc'
import { deleteFailedLog } from '#/utils/deleteLog'
import { IRPCActionType } from '#/types/enum'
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
try {
return ipcRenderer
? await ipcRenderer.invoke('delete-aws-s3-file',
getRawData(configMap)
)
? await triggerRPC(IRPCActionType.GALLERY_DELETE_AWS_S3_FILE, getRawData(configMap)) || false
: await removeFileFromS3InMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'AWS S3', error)

View File

@@ -1,15 +1,16 @@
import { ipcRenderer } from 'electron'
import { deleteFailedLog, getRawData } from '@/utils/common'
import { removeFileFromDogeInMain } from '~/utils/deleteFunc'
import { getRawData, triggerRPC } from '@/utils/common'
import { deleteFailedLog } from '#/utils/deleteLog'
import { IRPCActionType } from '#/types/enum'
export default class AwsS3Api {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
try {
return ipcRenderer
? await ipcRenderer.invoke('delete-doge-file',
getRawData(configMap)
)
? await triggerRPC(IRPCActionType.GALLERY_DELETE_DOGE_FILE, getRawData(configMap)) || false
: await removeFileFromDogeInMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'DogeCloud', error)

View File

@@ -1,6 +1,6 @@
import { Octokit } from '@octokit/rest'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,15 +1,16 @@
import { ipcRenderer } from 'electron'
import { deleteFailedLog, getRawData } from '@/utils/common'
import { removeFileFromHuaweiInMain } from '~/utils/deleteFunc'
import { getRawData, triggerRPC } from '@/utils/common'
import { deleteFailedLog } from '#/utils/deleteLog'
import { IRPCActionType } from '#/types/enum'
export default class HuaweicloudApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
try {
return ipcRenderer
? await ipcRenderer.invoke('delete-huaweicloud-file',
getRawData(configMap)
)
? await triggerRPC(IRPCActionType.GALLERY_DELETE_HUAWEI_OSS_FILE, getRawData(configMap)) || false
: await removeFileFromHuaweiInMain(getRawData(configMap))
} catch (error: any) {
deleteFailedLog(configMap.fileName, 'HuaweiCloud', error)

View File

@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
config?: Partial<IImgurConfig>

View File

@@ -1,6 +1,6 @@
import fs from 'fs-extra'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
hash: string

View File

@@ -1,7 +1,7 @@
import axios, { AxiosResponse } from 'axios'
import https from 'https'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
export default class LskyplistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {

View File

@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
export default class PiclistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {

View File

@@ -1,6 +1,6 @@
import Qiniu from 'qiniu'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,16 +1,19 @@
import { ipcRenderer } from 'electron'
import { deleteFailedLog, getRawData } from '@/utils/common'
import { removeFileFromSFTPInMain } from '~/utils/deleteFunc'
import { getRawData, triggerRPC } from '@/utils/common'
import { deleteFailedLog } from '#/utils/deleteLog'
import { IRPCActionType } from '#/types/enum'
export default class SftpPlistApi {
static async delete (configMap: IStringKeyMap): Promise<boolean> {
const { fileName, config } = configMap
try {
const deleteResult = await ipcRenderer.invoke('delete-sftp-file',
getRawData(config),
fileName
)
return deleteResult
return ipcRenderer
? await triggerRPC(IRPCActionType.GALLERY_DELETE_SFTP_FILE, getRawData(config),
fileName) || false
: await removeFileFromSFTPInMain(getRawData(config), fileName)
} catch (error: any) {
deleteFailedLog(fileName, 'SFTP', error)
return false

View File

@@ -1,6 +1,6 @@
import axios, { AxiosResponse } from 'axios'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
hash?: string

View File

@@ -1,6 +1,6 @@
import COS from 'cos-nodejs-sdk-v5'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,6 +1,6 @@
import Upyun from 'upyun'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
interface IConfigMap {
fileName: string

View File

@@ -1,7 +1,6 @@
import { AuthType, WebDAVClientOptions, createClient } from 'webdav'
import { deleteFailedLog, deleteLog } from '@/utils/common'
import { deleteFailedLog, deleteLog } from '#/utils/deleteLog'
import { formatEndpoint } from '#/utils/common'
interface IConfigMap {

View File

@@ -1,13 +1,14 @@
import { onMounted, onUnmounted } from 'vue'
import { openURL } from '@/utils/common'
import { sendRPC } from '@/utils/common'
import { IRPCActionType } from 'root/src/universal/types/enum'
export function useATagClick () {
const handleATagClick = (e: MouseEvent) => {
if (e.target instanceof HTMLAnchorElement) {
if (e.target.href) {
e.preventDefault()
openURL(e.target.href)
sendRPC(IRPCActionType.OPEN_URL, e.target.href)
}
}
}

View File

@@ -2,23 +2,34 @@ import { ipcRenderer } from 'electron'
import { ObjectAdapter, I18n } from '@picgo/i18n'
import bus from '@/utils/bus'
import { sendRPC } from '@/utils/common'
import { GET_CURRENT_LANGUAGE, SET_CURRENT_LANGUAGE, FORCE_UPDATE, GET_LANGUAGE_LIST } from '#/events/constants'
import { builtinI18nList } from '#/i18n'
import { IRPCActionType } from '#/types/enum'
export class I18nManager {
#i18n: I18n | null = null
#i18nFileList: II18nItem[] = builtinI18nList
constructor () {
this.#getCurrentLanguage()
this.#getLanguageList()
ipcRenderer.on(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
this.#setLocales(lang, locales)
bus.emit(FORCE_UPDATE)
})
}
#getLanguageList () {
ipcRenderer.send(GET_LANGUAGE_LIST)
sendRPC(IRPCActionType.GET_LANGUAGE_LIST)
ipcRenderer.once(GET_LANGUAGE_LIST, (_, list: II18nItem[]) => {
this.#i18nFileList = list
})
}
#getCurrentLanguage () {
ipcRenderer.send(GET_CURRENT_LANGUAGE)
sendRPC(IRPCActionType.GET_CURRENT_LANGUAGE)
ipcRenderer.once(GET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
this.#setLocales(lang, locales)
bus.emit(FORCE_UPDATE)
@@ -35,21 +46,12 @@ export class I18nManager {
})
}
constructor () {
this.#getCurrentLanguage()
this.#getLanguageList()
ipcRenderer.on(SET_CURRENT_LANGUAGE, (_, lang: string, locales: ILocales) => {
this.#setLocales(lang, locales)
bus.emit(FORCE_UPDATE)
})
}
T (key: ILocalesKey, args: IStringKeyMap = {}): string {
return this.#i18n?.translate(key, args) || key
}
setCurrentLanguage (lang: string) {
ipcRenderer.send(SET_CURRENT_LANGUAGE, lang)
sendRPC(IRPCActionType.SET_CURRENT_LANGUAGE, lang)
}
get languageList () {

View File

@@ -7,7 +7,7 @@
PicList - {{ version }}
</div>
<div
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
class="handle-bar"
>
<el-icon
@@ -68,7 +68,6 @@
:default-active="defaultActive"
:unique-opened="true"
@select="handleSelect"
@open="handleGetPicPeds"
>
<el-menu-item :index="routerConfig.UPLOAD_PAGE">
<el-icon>
@@ -101,7 +100,7 @@
<span>{{ $T('PICBEDS_SETTINGS') }}</span>
</template>
<template
v-for="item in picBed"
v-for="item in picBedGlobal"
>
<el-menu-item
v-if="item.visible"
@@ -188,7 +187,7 @@
teleported
>
<el-option
v-for="item in picBed"
v-for="item in picBedGlobal"
:key="item.type"
:label="item.name"
:value="item.type"
@@ -247,26 +246,21 @@ import InputBoxDialog from '@/components/InputBoxDialog.vue'
import { T as $T } from '@/i18n/index'
import * as config from '@/router/config'
import { getConfig, saveConfig } from '@/utils/dataSender'
import { openURL, sendToMain } from '@/utils/common'
import { sendRPC } from '@/utils/common'
import { osGlobal, picBedGlobal, updatePicBedGlobal } from '@/utils/global'
import {
MINIMIZE_WINDOW,
CLOSE_WINDOW,
SHOW_MAIN_PAGE_MENU,
SHOW_MAIN_PAGE_QRCODE,
GET_PICBEDS
SHOW_MAIN_PAGE_QRCODE
} from '#/events/constants'
import { configPaths, manualPageOpenType } from '#/utils/configPaths'
import { II18nLanguage } from '#/types/enum'
import { II18nLanguage, IRPCActionType } from '#/types/enum'
import pkg from 'root/package.json'
const version = ref(process.env.NODE_ENV === 'production' ? pkg.version : 'Dev')
const routerConfig = reactive(config)
const defaultActive = ref(routerConfig.UPLOAD_PAGE)
const os = ref('')
const $router = useRouter()
const picBed: Ref<IPicBedType[]> = ref([])
const qrcodeVisible = ref(false)
const picBedConfigString = ref('')
const choosedPicBedForQRCode: Ref<string[]> = ref([])
@@ -277,10 +271,7 @@ const isShowprogress = ref(false)
const progress = ref(0)
onBeforeMount(() => {
os.value = process.platform
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
handleGetPicPeds()
updatePicBedGlobal()
ipcRenderer.on(SHOW_MAIN_PAGE_QRCODE, () => {
qrcodeVisible.value = true
})
@@ -300,17 +291,13 @@ watch(() => choosedPicBedForQRCode, (val) => {
}
}, { deep: true })
const handleGetPicPeds = () => {
sendToMain(GET_PICBEDS)
}
const handleSelect = async (index: string) => {
defaultActive.value = index
if (index === routerConfig.DocumentPage) {
const manualPageOpenSetting = await getConfig<manualPageOpenType>(configPaths.settings.manualPageOpen)
const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
const openManual = () => ipcRenderer.send('openManualWindow')
const openExternal = () => openURL(lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html')
const openManual = () => sendRPC(IRPCActionType.OPEN_MANUAL_WINDOW)
const openExternal = () => sendRPC(IRPCActionType.OPEN_URL, lang === II18nLanguage.ZH_CN ? 'https://piclist.cn/app.html' : 'https://piclist.cn/en/app.html')
if (!manualPageOpenSetting) {
ElMessageBox.confirm($T('MANUAL_PAGE_OPEN_TIP'), $T('MANUAL_PAGE_OPEN_TIP_TITLE'), {
@@ -347,19 +334,19 @@ const handleSelect = async (index: string) => {
}
function minimizeWindow () {
sendToMain(MINIMIZE_WINDOW)
sendRPC(IRPCActionType.MINIMIZE_WINDOW)
}
function closeWindow () {
sendToMain(CLOSE_WINDOW)
sendRPC(IRPCActionType.CLOSE_WINDOW)
}
function openMenu () {
sendToMain(SHOW_MAIN_PAGE_MENU)
sendRPC(IRPCActionType.SHOW_MAIN_PAGE_MENU)
}
function openMiniWindow () {
sendToMain('openMiniWindow')
sendRPC(IRPCActionType.OPEN_MINI_WINDOW)
}
function handleCopyPicBedConfig () {
@@ -367,13 +354,9 @@ function handleCopyPicBedConfig () {
$message.success($T('COPY_PICBED_CONFIG_SUCCEED'))
}
function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
picBed.value = picBeds
}
function setAlwaysOnTop () {
isAlwaysOnTop.value = !isAlwaysOnTop.value
sendToMain('toggleMainWindowAlwaysOnTop', isAlwaysOnTop.value)
sendRPC(IRPCActionType.MAIN_WINDOW_ON_TOP)
}
onBeforeRouteUpdate(async (to) => {
@@ -385,7 +368,6 @@ onBeforeRouteUpdate(async (to) => {
})
onBeforeUnmount(() => {
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
ipcRenderer.removeAllListeners(SHOW_MAIN_PAGE_QRCODE)
ipcRenderer.removeAllListeners('updateProgress')
})

View File

@@ -1,34 +1,16 @@
import { ipcRenderer, IpcRendererEvent } from 'electron'
import { v4 as uuid } from 'uuid'
import { ipcRenderer } from 'electron'
import { getRawData } from '@/utils/common'
import { PICLIST_MANAGE_GET_CONFIG, PICLIST_MANAGE_SAVE_CONFIG, PICLIST_MANAGE_REMOVE_CONFIG } from '~/manage/events/constants'
export function getConfig<T> (key?: string): Promise<T | undefined> {
return new Promise((resolve) => {
const callbackId = uuid()
const callback = (_: IpcRendererEvent, config: T | undefined, returnCallbackId: string) => {
if (returnCallbackId === callbackId) {
resolve(config)
ipcRenderer.removeListener(PICLIST_MANAGE_GET_CONFIG, callback)
}
}
ipcRenderer.on(PICLIST_MANAGE_GET_CONFIG, callback)
ipcRenderer.send(PICLIST_MANAGE_GET_CONFIG, key, callbackId)
})
export function saveConfig (config: IObj | string, value?: any) {
const configObj = typeof config === 'string' ? { [config]: value } : getRawData(config)
ipcRenderer.send(PICLIST_MANAGE_SAVE_CONFIG, configObj)
}
export function saveConfig (_config: IObj | string, value?: any) {
let config
if (typeof _config === 'string') {
config = {
[_config]: value
}
} else {
config = getRawData(_config)
}
ipcRenderer.send(PICLIST_MANAGE_SAVE_CONFIG, config)
export async function getConfig<T> (key?: string): Promise<T | undefined> {
return await ipcRenderer.invoke(PICLIST_MANAGE_GET_CONFIG, key)
}
export function removeConfig (key: string, propName: string) {

View File

@@ -68,7 +68,7 @@
teleported
>
<el-option
v-for="item in picBed"
v-for="item in picBedGlobal"
:key="item.type"
:label="item.name"
:value="item.type"
@@ -462,8 +462,7 @@
<script lang="ts" setup>
import {
ipcRenderer,
clipboard,
IpcRendererEvent
clipboard
} from 'electron'
import { CheckboxValueType, ElMessageBox, ElNotification, ElMessage } from 'element-plus'
import { InfoFilled, Close, CaretBottom, Document, Edit, Delete, CaretTop, Sort, Refresh } from '@element-plus/icons-vue'
@@ -475,14 +474,14 @@ import type { IResult } from '@picgo/store/dist/types'
import ALLApi from '@/apis/allApi'
import { T as $T } from '@/i18n/index'
import { customRenameFormatTable, customStrMatch, customStrReplace } from '@/manage/utils/common'
import { sendToMain } from '@/utils/common'
import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig, saveConfig } from '@/utils/dataSender'
import $$db from '@/utils/db'
import { picBedGlobal } from '@/utils/global'
import { PASTE_TEXT, GET_PICBEDS } from '#/events/constants'
import { configPaths } from '#/utils/configPaths'
import { picBedsCanbeDeleted } from '#/utils/static'
import { IPasteStyle } from '#/types/enum'
import { IPasteStyle, IRPCActionType } from '#/types/enum'
const images = ref<ImgInfo[]>([])
const dialogVisible = ref(false)
@@ -529,7 +528,6 @@ const mathcedCount = computed(() => {
return matchedFiles.length
})
const dateRange = ref('')
const picBed = ref<IPicBedType[]>([])
onBeforeRouteUpdate((to, from) => {
if (from.name === 'gallery') {
clearChoosedList()
@@ -551,8 +549,6 @@ onBeforeMount(async () => {
updateGallery()
})
})
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
updateGallery()
document.addEventListener('keydown', handleDetectShiftKey)
@@ -588,10 +584,6 @@ function formatFileName (name: string) {
return path.basename(name)
}
function getPicBeds (event: IpcRendererEvent, picBeds: IPicBedType[]) {
picBed.value = picBeds
}
function getGallery (): IGalleryItem[] {
if (searchText.value || choosedPicBed.value.length > 0 || searchTextURL.value || dateRange.value) {
return images.value
@@ -636,7 +628,7 @@ function getGallery (): IGalleryItem[] {
}
async function updateGallery () {
images.value = (await $$db.get({ orderBy: 'desc' })).data
images.value = (await $$db.get({ orderBy: 'desc' }))!.data
}
watch(() => filterList, () => {
@@ -659,7 +651,7 @@ function handleChooseImage (val: CheckboxValueType, index: number) {
}
function refreshPage () {
ipcRenderer.send('refreshSettingWindow')
sendRPC(IRPCActionType.REFRESH_SETTING_WINDOW)
}
function clearChoosedList () {
@@ -694,7 +686,7 @@ function handleClose () {
async function copy (item: ImgInfo) {
item.config = JSON.parse(JSON.stringify(item.config) || '{}')
const copyLink = await ipcRenderer.invoke(PASTE_TEXT, item)
const copyLink = await triggerRPC<string>(IRPCActionType.GALLERY_PASTE_TEXT, item)
const obj = {
title: $T('COPY_LINK_SUCCEED'),
body: copyLink
@@ -733,7 +725,7 @@ function remove (item: ImgInfo) {
}
}
await $$db.removeById(item.id!)
sendToMain('removeFiles', [file])
sendRPC(IRPCActionType.GALLERY_REMOVE_FILES, [file])
const obj = {
title: $T('OPERATION_SUCCEED'),
body: ''
@@ -858,7 +850,7 @@ function multiRemove () {
title: $T('OPERATION_SUCCEED'),
body: ''
}
sendToMain('removeFiles', files)
sendRPC(IRPCActionType.GALLERY_REMOVE_FILES, files)
const myNotification = new Notification(obj.title, obj)
myNotification.onclick = () => {
return true
@@ -880,8 +872,8 @@ async function multiCopy () {
if (choosedList[key]) {
const item = await $$db.getById<ImgInfo>(key)
if (item) {
const txt = await ipcRenderer.invoke(PASTE_TEXT, item)
copyString.push(txt)
const txt = await triggerRPC<string>(IRPCActionType.GALLERY_PASTE_TEXT, item)
copyString.push(txt!)
choosedList[key] = false
}
}
@@ -1026,7 +1018,6 @@ function handleBatchRename () {
onBeforeUnmount(() => {
ipcRenderer.removeAllListeners('updateGallery')
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
})
onActivated(async () => {

View File

@@ -4,7 +4,7 @@
>
<div
id="upload-area"
:class="{ 'is-dragover': dragover, uploading: isShowingProgress, linux: os === 'linux' }"
:class="{ 'is-dragover': dragover, uploading: isShowingProgress, linux: osGlobal === 'linux' }"
:style="{ backgroundPosition: '0 ' + progress + '%'}"
@drop.prevent="onDrop"
@dragover.prevent="dragover = true"
@@ -40,11 +40,12 @@ import { IConfig } from 'piclist'
import { onBeforeUnmount, onBeforeMount, ref, watch } from 'vue'
import { T as $T } from '@/i18n/index'
import { sendToMain, invokeToMain } from '@/utils/common'
import { invokeToMain, sendRPC } from '@/utils/common'
import { getConfig } from '@/utils/dataSender'
import { osGlobal } from '@/utils/global'
import { SHOW_MINI_PAGE_MENU, SET_MINI_WINDOW_POS } from '#/events/constants'
import { isUrl } from '#/utils/common'
import { IRPCActionType } from '#/types/enum'
const logoPath = ref('')
const dragover = ref(false)
@@ -55,11 +56,10 @@ const wX = ref(-1)
const wY = ref(-1)
const screenX = ref(-1)
const screenY = ref(-1)
const os = ref('')
async function initLogoPath () {
const config = (await getConfig<IConfig>())!
if (config !== undefined) {
const config = await getConfig<IConfig>()
if (config) {
if (config.settings?.isCustomMiniIcon && config.settings?.customMiniIcon) {
logoPath.value = 'data:image/jpg;base64,' + await invokeToMain('convertPathToBase64', config.settings.customMiniIcon)
}
@@ -67,7 +67,6 @@ async function initLogoPath () {
}
onBeforeMount(async () => {
os.value = process.platform
await initLogoPath()
ipcRenderer.on('uploadProgress', (_: IpcRendererEvent, _progress: number) => {
if (_progress !== -1) {
@@ -110,7 +109,7 @@ function onDrop (e: DragEvent) {
} else if (items[0].type === 'text/plain') {
const str = e.dataTransfer!.getData(items[0].type)
if (isUrl(str)) {
sendToMain('uploadChoosedFiles', [{ path: str }])
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
} else {
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
@@ -124,7 +123,7 @@ function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer)
const urlString = dataTransfer.getData(items[1].type)
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
if (urlMatch) {
sendToMain('uploadChoosedFiles', [
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
{
path: urlMatch[1]
}
@@ -154,7 +153,7 @@ function ipcSendFiles (files: FileList) {
}
sendFiles.push(obj)
})
sendToMain('uploadChoosedFiles', sendFiles)
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, sendFiles)
}
function handleMouseDown (e: MouseEvent) {
@@ -171,7 +170,7 @@ function handleMouseMove (e: MouseEvent) {
if (draggingState.value) {
const xLoc = e.screenX - wX.value
const yLoc = e.screenY - wY.value
sendToMain(SET_MINI_WINDOW_POS, {
sendRPC(IRPCActionType.SET_MINI_WINDOW_POS, {
x: xLoc,
y: yLoc,
width: 64,
@@ -192,7 +191,7 @@ function handleMouseUp (e: MouseEvent) {
}
function openContextMenu () {
sendToMain(SHOW_MINI_PAGE_MENU)
sendRPC(IRPCActionType.SHOW_MINI_PAGE_MENU)
}
onBeforeUnmount(() => {

View File

@@ -74,13 +74,13 @@
:value="'quiet'"
/>
<el-option
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
key="mini"
:label="$T('SETTINGS_START_MODE_MINI')"
:value="'mini'"
/>
<el-option
v-if="os === 'darwin'"
v-if="osGlobal === 'darwin'"
key="no-tray"
:label="$T('SETTINGS_START_MODE_NO_TRAY')"
:value="'no-tray'"
@@ -113,7 +113,7 @@
</el-select>
</el-form-item>
<el-form-item
v-if="os === 'darwin'"
v-if="osGlobal === 'darwin'"
:label="$T('SETTINGS_ISHIDEDOCK')"
>
<el-switch
@@ -136,7 +136,7 @@
</el-button>
</el-form-item>
<el-form-item
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
:label="$T('SETTINGS_CLOSE_MINI_WINDOW_SYNC')"
>
<el-switch
@@ -146,7 +146,7 @@
/>
</el-form-item>
<el-form-item
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
:label="$T('SETTINGS_CLOSE_MAIN_WINDOW_SYNC')"
>
<el-switch
@@ -156,7 +156,7 @@
/>
</el-form-item>
<el-form-item
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
:label="$T('SETTINGS_MINI_WINDOW_ON_TOP')"
>
<el-switch
@@ -167,7 +167,7 @@
/>
</el-form-item>
<el-form-item
v-if="os !== 'darwin'"
v-if="osGlobal !== 'darwin'"
:label="$T('SETTINGS_CUSTOM_MINI_ICON')"
>
<el-switch
@@ -177,7 +177,7 @@
/>
</el-form-item>
<el-form-item
v-if="os !== 'darwin' && formOfSetting.isCustomMiniIcon"
v-if="osGlobal !== 'darwin' && formOfSetting.isCustomMiniIcon"
:label="$T('SETTINGS_CUSTOM_MINI_ICON_PATH')"
>
<el-button
@@ -336,7 +336,7 @@
teleported
>
<el-option
v-for="item in picBed"
v-for="item in picBedGlobal"
:key="item.type"
:label="item.name"
:value="item.type"
@@ -425,7 +425,7 @@
:label="$T('SETTINGS_AUTO_COPY_URL_AFTER_UPLOAD')"
>
<el-switch
v-model="formOfSetting.autoCopyUrl"
v-model="formOfSetting.autoCopy"
:active-text="$T('SETTINGS_OPEN')"
:inactive-text="$T('SETTINGS_CLOSE')"
/>
@@ -563,11 +563,11 @@
:label="$T('CHOOSE_SHOWED_PICBED')"
>
<el-checkbox-group
v-model="formOfSetting.showPicBedList"
v-model="showPicBedList"
@change="handleShowPicBedListChange"
>
<el-checkbox
v-for="item in picBed"
v-for="item in picBedGlobal"
:key="item.name"
:label="item.name"
:value="item.name"
@@ -730,7 +730,7 @@
<el-form
ref="$customLink"
label-position="top"
:model="formOfSetting.customLink"
:model="customLink"
:rules="rules"
size="small"
>
@@ -745,7 +745,7 @@
{{ $T('SETTINGS_TIPS_PLACEHOLDER_EXTNAME') }}
</div>
<el-input
v-model="formOfSetting.customLink"
v-model="customLink.value"
class="align-center"
:autofocus="true"
/>
@@ -781,7 +781,6 @@
>
<el-form
label-position="right"
:model="formOfSetting.customLink"
label-width="120px"
>
<el-form-item
@@ -825,7 +824,6 @@
>
<el-form
label-position="right"
:model="formOfSetting.customLink"
label-width="120px"
>
<el-form-item
@@ -1378,27 +1376,26 @@
<script lang="ts" setup>
import { compare } from 'compare-versions'
import { ipcRenderer } from 'electron'
import { ElForm, ElMessage as $message, ElMessage, ElMessageBox, FormRules } from 'element-plus'
import { Reading, Close, Edit, InfoFilled } from '@element-plus/icons-vue'
import { IConfig } from 'piclist'
import { computed, onBeforeMount, onBeforeUnmount, reactive, ref, toRaw, watch } from 'vue'
import { computed, onBeforeMount, reactive, ref, toRaw, watch } from 'vue'
import { useRouter } from 'vue-router'
import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
import { i18nManager, T as $T } from '@/i18n/index'
import { buildInRenameFormatTable } from '@/manage/utils/common'
import { SHORTKEY_PAGE } from '@/router/config'
import { getConfig, saveConfig, sendRPC } from '@/utils/dataSender'
import { getConfig, saveConfig } from '@/utils/dataSender'
import { osGlobal, picBedGlobal, updatePicBedGlobal } from '@/utils/global'
import { PICGO_OPEN_FILE, PICGO_OPEN_DIRECTORY, OPEN_URL, GET_PICBEDS, HIDE_DOCK } from '#/events/constants'
import { II18nLanguage, IRPCActionType, ISartMode } from '#/types/enum'
import { enforceNumber } from '#/utils/common'
import { configPaths, ISartModeValues } from '#/utils/configPaths'
import { getLatestVersion } from '#/utils/getLatestVersion'
import pkg from 'root/package.json'
import { invokeToMain, sendToMain } from '@/utils/common'
import { invokeToMain, sendRPC, triggerRPC } from '@/utils/common'
const $router = useRouter()
const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system')
@@ -1435,7 +1432,12 @@ const manualPageOpenList = [{
value: 'browser'
}]
const picBed = ref<IPicBedType[]>([])
const showPicBedList = computed(() => picBedGlobal.value.map(item => {
if (item.visible) {
return item.name
}
return null
}).filter(item => item) as string[])
const $customLink = ref<InstanceType<typeof ElForm> | null>(null)
@@ -1447,9 +1449,8 @@ const customLinkRule = (_: any, value: string, callback: (arg0?: Error) => void)
}
}
const formOfSetting = ref<IStringKeyMap>({
const formOfSetting = ref<ISettingForm>({
showUpdateTip: true,
showPicBedList: [],
autoStart: false,
rename: false,
autoRename: false,
@@ -1483,29 +1484,33 @@ const formOfSetting = ref<IStringKeyMap>({
webServerHost: '0.0.0.0',
webServerPort: 37777,
webServerPath: '',
customLink: '![$fileName]($url)',
registry: '',
proxy: '',
mainWindowWidth: 1200,
mainWindowHeight: 800
})
const proxy = ref('')
const formKeys = Object.keys(formOfSetting.value)
const autoWatchKeys = ['showUpdateTip', 'autoImport', 'autoImportPicBed', 'useBuiltinClipboard', 'isAutoListenClipboard', 'deleteCloudFile', 'deleteLocalFile', 'rename', 'autoRename', 'enableWebServer', 'webServerHost', 'webServerPath', 'serverKey', 'uploadNotification', 'uploadResultNotification', 'autoCloseMainWindow', 'autoCloseMiniWindow', 'isCustomMiniIcon', 'c1nToken', 'yourlsDomain', 'yourlsSignature', 'cfWorkerHost', 'registry', 'proxy', 'autoCopy', 'encodeOutputURL', 'useShortUrl']
autoWatchKeys.forEach(key => {
watch(() => formOfSetting.value[key], (value) => {
saveConfig({
[`settings.${key}`]: value
const addWatch = () => {
autoWatchKeys.forEach(key => {
watch(() => formOfSetting.value[key as keyof ISettingForm], value => {
saveConfig({
[`settings.${key}`]: value
})
})
})
})
}
watch(proxy, (value) => {
saveConfig({
'picBed.proxy': value
const addProxyWatch = () => {
watch(proxy, (value) => {
saveConfig({
'picBed.proxy': value
})
})
})
}
const valueToOptionItem = (value: any, list: { label: string, value: any }[]) => {
return list.find(item => item.value === value) || list[0]
@@ -1530,6 +1535,10 @@ const imageProcessDialogVisible = ref(false)
const rawPicGoSize = ref(false)
const customLink = reactive({
value: '![$fileName]($url)'
})
const rules = reactive<FormRules>({
value: [
{ validator: customLinkRule, trigger: 'blur' }
@@ -1592,7 +1601,6 @@ function confirmSyncSetting () {
const version = pkg.version
const latestVersion = ref('')
const os = ref('')
const needUpdate = computed(() => {
if (latestVersion.value) {
@@ -1602,9 +1610,6 @@ const needUpdate = computed(() => {
})
onBeforeMount(() => {
os.value = process.platform
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
initData()
})
@@ -1613,7 +1618,7 @@ async function initData () {
const settings = config.settings || {}
const picBed = config.picBed
formKeys.forEach(key => {
formOfSetting.value[key] = settings[key] ?? formOfSetting.value[key]
(formOfSetting.value as any)[key as keyof ISettingForm] = settings[key] ?? formOfSetting.value[key as keyof ISettingForm]
})
formOfSetting.value.logLevel = initArray(settings.logLevel || [], ['all'])
formOfSetting.value.autoImportPicBed = initArray(settings.autoImportPicBed || [], [])
@@ -1621,6 +1626,7 @@ async function initData () {
currentStartMode.value = valueToOptionItem(settings.startMode || ISartMode.QUIET, startModeList)
currentManualPageOpen.value = valueToOptionItem(settings.manualPageOpen || 'window', manualPageOpenList)
currentShortUrlServer.value = valueToOptionItem(settings.shortUrlServer || 'c1n', shortUrlServerList)
customLink.value = settings.customLink || '![$fileName]($url)'
proxy.value = picBed.proxy || ''
server.value = settings.server || {
port: 36677,
@@ -1648,6 +1654,8 @@ async function initData () {
interval: 60
}
formOfSetting.value.logFileSizeLimit = enforceNumber(settings.logFileSizeLimit) || 10
addProxyWatch()
addWatch()
}
function initArray (arrayT: string | string[], defaultValue: string[]) {
@@ -1661,18 +1669,8 @@ function initArray (arrayT: string | string[], defaultValue: string[]) {
return arrayT
}
function getPicBeds (_: Event, picBeds: IPicBedType[]) {
picBed.value = picBeds
formOfSetting.value.showPicBedList = picBed.value.map(item => {
if (item.visible) {
return item.name
}
return null
}).filter(item => item) as string[]
}
function openFile (file: string) {
sendToMain(PICGO_OPEN_FILE, file)
sendRPC(IRPCActionType.PICLIST_OPEN_FILE, file)
}
function handleManualPageOpenChange (val: string) {
@@ -1682,7 +1680,7 @@ function handleManualPageOpenChange (val: string) {
}
function openDirectory (directory?: string, inStorePath = true) {
sendToMain(PICGO_OPEN_DIRECTORY, directory, inStorePath)
sendRPC(IRPCActionType.PICLIST_OPEN_DIRECTORY, directory, inStorePath)
}
function openLogSetting () {
@@ -1691,13 +1689,13 @@ function openLogSetting () {
async function cancelCustomLink () {
customLinkVisible.value = false
formOfSetting.value.customLink = await getConfig<string>(configPaths.settings.customLink) || '![$fileName]($url)'
customLink.value = await getConfig<string>(configPaths.settings.customLink) || '![$fileName]($url)'
}
function confirmCustomLink () {
$customLink.value?.validate((valid: boolean) => {
if (valid) {
saveConfig(configPaths.settings.customLink, formOfSetting.value.customLink)
saveConfig(configPaths.settings.customLink, customLink.value)
customLinkVisible.value = false
}
})
@@ -1721,17 +1719,21 @@ function handleSaveAdvancedRename () {
}
function handleMigrateFromPicGo () {
ElMessageBox.confirm($T('SETTINGS_MIGRATE_FROM_PICGO_CONTENT'), $T('SETTINGS_MIGRATE_FROM_PICGO_TITLE'), {
confirmButtonText: $T('CONFIRM'),
cancelButtonText: $T('CANCEL'),
type: 'warning',
center: true
}).then(() => {
ipcRenderer.invoke('migrateFromPicGo').then(() => {
ElMessage.success($T('SETTINGS_MIGRATE_FROM_PICGO_SUCCESS'))
}).catch(() => {
ElMessage.error($T('SETTINGS_MIGRATE_FROM_PICGO_FAILED'))
})
ElMessageBox.confirm(
$T('SETTINGS_MIGRATE_FROM_PICGO_CONTENT'),
$T('SETTINGS_MIGRATE_FROM_PICGO_TITLE'), {
confirmButtonText: $T('CONFIRM'),
cancelButtonText: $T('CANCEL'),
type: 'warning',
center: true
}).then(() => {
triggerRPC<boolean>(IRPCActionType.CONFIGURE_MIGRATE_FROM_PICGO)
.then(() => {
ElMessage.success($T('SETTINGS_MIGRATE_FROM_PICGO_SUCCESS'))
})
.catch(() => {
ElMessage.error($T('SETTINGS_MIGRATE_FROM_PICGO_FAILED'))
})
}).catch(() => {
return false
})
@@ -1744,11 +1746,11 @@ function handleHideDockChange (val: ICheckBoxValueType) {
return
}
saveConfig(configPaths.settings.isHideDock, val)
sendToMain(HIDE_DOCK, val)
sendRPC(IRPCActionType.HIDE_DOCK, val)
}
function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
const list = picBed.value.map(item => {
const list = picBedGlobal.value.map(item => {
if (!val.includes(item.name)) {
item.visible = false
} else {
@@ -1759,12 +1761,12 @@ function handleShowPicBedListChange (val: ICheckBoxValueType[]) {
saveConfig({
[configPaths.picBed.list]: list
})
sendToMain(GET_PICBEDS)
updatePicBedGlobal()
}
function handleAutoStartChange (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.autoStart, val)
sendToMain('autoStart', val)
sendRPC(IRPCActionType.PICLIST_AUTO_START, val)
}
function compareVersion2Update (current: string, latest: string): boolean {
@@ -1793,9 +1795,9 @@ function handleWebServerPortChange (val?: number, _?: number) {
function confirmWebServerSetting () {
if (formOfSetting.value.enableWebServer) {
sendToMain('restartWebServer')
sendRPC(IRPCActionType.ADVANCED_RESTART_WEB_SERVER)
} else {
sendToMain('stopWebServer')
sendRPC(IRPCActionType.ADVANCED_STOP_WEB_SERVER)
}
}
@@ -1822,7 +1824,7 @@ async function confirmWindowSize () {
function handleMiniWindowOntop (val: ICheckBoxValueType) {
saveConfig(configPaths.settings.miniWindowOntop, val)
ipcRenderer.send('miniWindowOntop', val)
sendRPC(IRPCActionType.MINI_WINDOW_ON_TOP, val)
}
async function handleMiniIconPath (_: Event) {
@@ -1830,7 +1832,7 @@ async function handleMiniIconPath (_: Event) {
if (result && result[0]) {
formOfSetting.value.customMiniIcon = result[0]
saveConfig(configPaths.settings.customMiniIcon, formOfSetting.value.customMiniIcon)
ipcRenderer.send('updateMiniIcon', formOfSetting.value.customMiniIcon)
sendRPC(IRPCActionType.UPDATE_MINI_WINDOW_ICON, formOfSetting.value.customMiniIcon)
}
}
@@ -1879,40 +1881,40 @@ function syncMessage (failed: number, taskType: 'UPLOAD' | 'DOWNLOAD') {
const syncTaskList = [
{
task: 'uploadCommonConfig',
task: IRPCActionType.CONFIGURE_UPLOAD_COMMON_CONFIG,
label: $T('SETTINGS_SYNC_COMMON_CONFIG'),
number: 2
},
{
task: 'uploadManageConfig',
task: IRPCActionType.CONFIGURE_UPLOAD_MANAGE_CONFIG,
label: $T('SETTINGS_SYNC_MANAGE_CONFIG'),
number: 2
},
{
task: 'uploadAllConfig',
task: IRPCActionType.CONFIGURE_UPLOAD_ALL_CONFIG,
label: $T('SETTINGS_SYNC_UPLOAD_ALL'),
number: 4
},
{
task: 'downloadCommonConfig',
task: IRPCActionType.CONFIGURE_DOWNLOAD_COMMON_CONFIG,
label: $T('SETTINGS_SYNC_COMMON_CONFIG'),
number: 2
},
{
task: 'downloadManageConfig',
task: IRPCActionType.CONFIGURE_DOWNLOAD_MANAGE_CONFIG,
label: $T('SETTINGS_SYNC_MANAGE_CONFIG'),
number: 2
},
{
task: 'downloadAllConfig',
task: IRPCActionType.CONFIGURE_DOWNLOAD_ALL_CONFIG,
label: $T('SETTINGS_SYNC_DOWNLOAD_ALL'),
number: 4
}
]
async function syncTaskFn (task: string, number: number) {
const failed = number - await invokeToMain(task)
syncMessage(failed, task.includes('upload') ? 'UPLOAD' : 'DOWNLOAD')
async function syncTaskFn (task: IRPCActionType, number: number) {
const failed = number - (await triggerRPC<number>(task) || 0)
syncMessage(failed, task.includes('UPLOAD') ? 'UPLOAD' : 'DOWNLOAD')
}
function confirmServerSetting () {
@@ -1921,7 +1923,7 @@ function confirmServerSetting () {
[configPaths.settings.server]: server.value
})
serverVisible.value = false
sendToMain('updateServer')
sendRPC(IRPCActionType.ADVANCED_UPDATE_SERVER)
}
async function cancelServerSetting () {
@@ -1959,7 +1961,7 @@ function handleLanguageChange (val: string) {
saveConfig({
[configPaths.settings.language]: val
})
sendToMain(GET_PICBEDS)
updatePicBedGlobal()
}
function handleStartModeChange (val: ISartModeValues) {
@@ -1981,7 +1983,7 @@ async function goConfigPage () {
const url = lang === II18nLanguage.ZH_CN
? 'https://piclist.cn/configure.html'
: 'https://piclist.cn/en/configure.html'
sendToMain(OPEN_URL, url)
sendRPC(IRPCActionType.OPEN_URL, url)
}
function goShortCutPage () {
@@ -1990,10 +1992,6 @@ function goShortCutPage () {
})
}
onBeforeUnmount(() => {
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
})
</script>
<script lang="ts">
export default {

View File

@@ -80,7 +80,7 @@
>
<div
class="plugin-item"
:class="{ 'darwin': os === 'darwin' }"
:class="{ 'darwin': osGlobal === 'darwin' }"
>
<div
v-if="!item.gui"
@@ -241,16 +241,14 @@ import { computed, ref, onBeforeMount, onBeforeUnmount, watch, onMounted, reacti
import ConfigForm from '@/components/ConfigFormForPlugin.vue'
import { T as $T } from '@/i18n/index'
import { sendToMain } from '@/utils/common'
import { getConfig, saveConfig, sendRPC } from '@/utils/dataSender'
import { sendRPC } from '@/utils/common'
import { getConfig, saveConfig } from '@/utils/dataSender'
import { osGlobal, updatePicBedGlobal } from '@/utils/global'
import {
OPEN_URL,
PICGO_CONFIG_PLUGIN,
PICGO_HANDLE_PLUGIN_ING,
PICGO_TOGGLE_PLUGIN,
SHOW_PLUGIN_PAGE_MENU,
GET_PICBEDS,
PICGO_HANDLE_PLUGIN_DONE
} from '#/events/constants'
import { IRPCActionType } from '#/types/enum'
@@ -272,7 +270,6 @@ const pluginListToolTip = $T('PLUGIN_LIST')
const importLocalPluginToolTip = $T('PLUGIN_IMPORT_LOCAL')
const updateAllToolTip = $T('PLUGIN_UPDATE_ALL')
// const id = ref('')
const os = ref('')
const defaultLogo = ref(`this.src="file://${__static.replace(/\\/g, '/')}/roundLogo.png"`)
const $configForm = ref<InstanceType<typeof ConfigForm> | null>(null)
const npmSearchText = computed(() => {
@@ -314,7 +311,6 @@ async function getLatestVersionOfPlugIn (pluginName: string) {
}
onBeforeMount(async () => {
os.value = process.platform
ipcRenderer.on('hideLoading', () => {
loading.value = false
})
@@ -353,7 +349,7 @@ onBeforeMount(async () => {
item.ing = false
item.hasInstall = true
}
getPicBeds()
updatePicBedGlobal()
})
handleReload()
getPluginList()
@@ -368,7 +364,7 @@ onBeforeMount(async () => {
if (item.config.uploader.name) {
handleRestoreState('uploader', item.config.uploader.name)
}
getPicBeds()
updatePicBedGlobal()
}
return item.fullName !== plugin
})
@@ -392,7 +388,7 @@ onBeforeMount(async () => {
const plugin = pluginList.value.find(item => item.fullName === fullName)
if (plugin) {
plugin.enabled = enabled
getPicBeds()
updatePicBedGlobal()
needReload.value = true
}
})
@@ -402,7 +398,7 @@ onBeforeMount(async () => {
})
async function buildContextMenu (plugin: IPicGoPlugin) {
sendToMain(SHOW_PLUGIN_PAGE_MENU, plugin)
sendRPC(IRPCActionType.SHOW_PLUGIN_PAGE_MENU, plugin)
}
function handleResize () {
@@ -417,11 +413,7 @@ onMounted(() => {
})
function getPluginList () {
sendToMain('getPluginList')
}
function getPicBeds () {
sendToMain(GET_PICBEDS)
sendRPC(IRPCActionType.PLUGIN_GET_LIST)
}
function installPlugin (item: IPicGoPlugin) {
@@ -432,13 +424,13 @@ function installPlugin (item: IPicGoPlugin) {
type: 'warning'
}).then(() => {
item.ing = true
sendToMain('installPlugin', item.fullName)
sendRPC(IRPCActionType.PLUGIN_INSTALL, item.fullName)
}).catch(() => {
console.log('Install canceled')
})
} else {
item.ing = true
sendToMain('installPlugin', item.fullName)
sendRPC(IRPCActionType.PLUGIN_INSTALL, item.fullName)
}
}
@@ -558,21 +550,21 @@ async function handleRestoreState (item: string, name: string) {
function openHomepage (url: string) {
if (url) {
sendToMain(OPEN_URL, url)
sendRPC(IRPCActionType.OPEN_URL, url)
}
}
function goAwesomeList () {
sendToMain(OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo')
sendRPC(IRPCActionType.OPEN_URL, 'https://github.com/PicGo/Awesome-PicGo')
}
function handleImportLocalPlugin () {
sendToMain('importLocalPlugin')
sendRPC(IRPCActionType.PLUGIN_IMPORT_LOCAL)
loading.value = true
}
function handleUpdateAllPlugin () {
sendToMain('updateAllPlugin', toRaw(pluginNameList.value))
sendRPC(IRPCActionType.PLUGIN_UPDATE_ALL, toRaw(pluginNameList.value))
}
onBeforeUnmount(() => {

View File

@@ -118,16 +118,15 @@
</template>
<script lang="ts" setup>
import { ipcRenderer, IpcRendererEvent } from 'electron'
import { onBeforeUnmount, onBeforeMount, ref, watch } from 'vue'
import { T as $T } from '@/i18n'
import { sendToMain } from '@/utils/common'
import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig } from '@/utils/dataSender'
import keyBinding from '@/utils/key-binding'
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '#/events/constants'
import { configPaths } from '#/utils/configPaths'
import { IRPCActionType } from '#/types/enum'
const list = ref<IShortKeyConfig[]>([])
const keyBindingVisible = ref(false)
@@ -146,7 +145,7 @@ onBeforeMount(async () => {
})
watch(keyBindingVisible, (val: boolean) => {
sendToMain(TOGGLE_SHORTKEY_MODIFIED_MODE, val)
sendRPC(IRPCActionType.SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE, val)
})
function calcOrigin (item: string) {
@@ -161,7 +160,7 @@ function calcOriginShowName (item: string) {
function toggleEnable (item: IShortKeyConfig) {
const status = !item.enable
item.enable = status
sendToMain('bindOrUnbindShortKey', item, item.from)
sendRPC(IRPCActionType.SHORTKEY_BIND_OR_UNBIND, item, item.from)
}
function keyDetect (event: KeyboardEvent) {
@@ -184,24 +183,24 @@ async function confirmKeyBinding () {
const oldKey = await getConfig<string>(`settings.shortKey.${command.value}.key`)
const config = Object.assign({}, list.value[currentIndex.value])
config.key = shortKey.value
sendToMain('updateShortKey', config, oldKey, config.from)
ipcRenderer.once('updateShortKeyResponse', (_: IpcRendererEvent, result) => {
if (result) {
keyBindingVisible.value = false
list.value[currentIndex.value].key = shortKey.value
}
})
const result = await triggerRPC<boolean>(IRPCActionType.SHORTKEY_UPDATE, config, oldKey, config.from)
if (result) {
keyBindingVisible.value = false
list.value[currentIndex.value].key = shortKey.value
}
}
onBeforeUnmount(() => {
sendToMain(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
sendRPC(IRPCActionType.SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE, false)
})
</script>
<script lang="ts">
export default {
name: 'ShortkeyPage'
}
</script>
<style lang='stylus'>
#shortcut-page
.shortcut-page-table-border

View File

@@ -103,9 +103,9 @@ import ToolboxStatusIcon from '@/components/ToolboxStatusIcon.vue'
import ToolboxHandler from '@/components/ToolboxHandler.vue'
import { useIPC } from '@/hooks/useIPC'
import { T as $T } from '@/i18n'
import { sendRPC, triggerRPC } from '@/utils/dataSender'
import { IToolboxItemType, IToolboxItemCheckStatus, IRPCActionType } from '#/types/enum'
import { sendRPC, triggerRPC } from '@/utils/common'
const $confirm = ElMessageBox.confirm
const defaultLogo = ref(`file://${__static.replace(/\\/g, '/')}/roundLogo.png`)

View File

@@ -67,13 +67,12 @@ import { reactive, ref, onBeforeUnmount, onBeforeMount } from 'vue'
import { IResult } from '@picgo/store/dist/types'
import { T as $T } from '@/i18n/index'
import { sendToMain } from '@/utils/common'
import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig } from '@/utils/dataSender'
import $$db from '@/utils/db'
import { IPasteStyle, IWindowList } from '#/types/enum'
import { OPEN_WINDOW } from '#/events/constants'
import { IPasteStyle, IRPCActionType, IWindowList } from '#/types/enum'
import { handleUrlEncode } from '#/utils/common'
import { configPaths } from '#/utils/configPaths'
@@ -87,11 +86,11 @@ const clipboardFiles = ref<ImgInfo[]>([])
const uploadFlag = ref(false)
function openSettingWindow () {
sendToMain(OPEN_WINDOW, IWindowList.SETTING_WINDOW)
sendRPC(IRPCActionType.OPEN_WINDOW, IWindowList.SETTING_WINDOW)
}
async function getData () {
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 }))!.data
}
const formatCustomLink = (customLink: string, item: ImgInfo) => {
@@ -134,7 +133,7 @@ async function pasteTemplate (style: IPasteStyle, item: ImgInfo, customLink: str
}
const useShortUrl = await getConfig(configPaths.settings.useShortUrl) || false
if (useShortUrl) {
url = await ipcRenderer.invoke('getShortUrl', url)
url = await triggerRPC<string>(IRPCActionType.TRAY_GET_SHORT_URL, url) || url
}
notification.body = url
const _customLink = customLink || '![$fileName]($url)'
@@ -167,7 +166,7 @@ function uploadClipboardFiles () {
return
}
uploadFlag.value = true
sendToMain('uploadClipboardFiles')
sendRPC(IRPCActionType.TRAY_UPLOAD_CLIPBOARD_FILES)
}
onBeforeMount(() => {
@@ -178,13 +177,13 @@ onBeforeMount(() => {
const item = _files[i]
await $$db.insert(item)
}
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 }))!.data
})
ipcRenderer.on('clipboardFiles', (_: Event, files: ImgInfo[]) => {
clipboardFiles.value = files
})
ipcRenderer.on('uploadFiles', async () => {
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 })).data
files.value = (await $$db.get<ImgInfo>({ orderBy: 'desc', limit: 5 }))!.data
uploadFlag.value = false
})
ipcRenderer.on('updateFiles', () => {

View File

@@ -164,14 +164,13 @@ import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
import { T as $T } from '@/i18n'
import { PICBEDS_PAGE } from '@/router/config'
import $bus from '@/utils/bus'
import { sendToMain } from '@/utils/common'
import { getConfig, saveConfig, triggerRPC } from '@/utils/dataSender'
import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig, saveConfig } from '@/utils/dataSender'
import { picBedGlobal, updatePicBedGlobal } from '@/utils/global'
import {
SHOW_INPUT_BOX,
SHOW_INPUT_BOX_RESPONSE,
SHOW_UPLOAD_PAGE_MENU,
GET_PICBEDS
SHOW_INPUT_BOX_RESPONSE
} from '#/events/constants'
import { IPasteStyle, IRPCActionType } from '#/types/enum'
import {
@@ -188,7 +187,6 @@ const progress = ref(0)
const showProgress = ref(false)
const showError = ref(false)
const pasteStyle = ref('')
const picBed = ref<IPicBedType[]>([])
const picBedName = ref('')
const picBedConfigName = ref('')
@@ -200,7 +198,12 @@ const pasteFormatList = ref({
[IPasteStyle.CUSTOM]: ''
})
watch(picBedGlobal, () => {
getDefaultPicBed()
})
onBeforeMount(() => {
updatePicBedGlobal()
ipcRenderer.on('uploadProgress', (_event: IpcRendererEvent, _progress: number) => {
if (_progress !== -1) {
showProgress.value = true
@@ -216,8 +219,6 @@ onBeforeMount(() => {
ipcRenderer.on('syncPicBed', () => {
getDefaultPicBed()
})
sendToMain(GET_PICBEDS)
ipcRenderer.on(GET_PICBEDS, getPicBeds)
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
})
@@ -243,7 +244,7 @@ async function handlePicBedNameClick (_picBedName: string, picBedConfigName: str
const formatedpicBedConfigName = picBedConfigName || 'Default'
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
const currentPicBedConfig = await getConfig<any[]>(`uploader.${currentPicBed}`) as any || {}
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, currentPicBed)
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, currentPicBed)
const currentConfigList = configList?.configList ?? []
const config = currentConfigList.find((item: any) => item._configName === formatedpicBedConfigName)
$router.push({
@@ -262,7 +263,6 @@ onBeforeUnmount(() => {
$bus.off(SHOW_INPUT_BOX_RESPONSE)
ipcRenderer.removeAllListeners('uploadProgress')
ipcRenderer.removeAllListeners('syncPicBed')
ipcRenderer.removeListener(GET_PICBEDS, getPicBeds)
})
function onDrop (e: DragEvent) {
@@ -279,7 +279,7 @@ function onDrop (e: DragEvent) {
} else if (items[0].type === 'text/plain') {
const str = e.dataTransfer!.getData(items[0].type)
if (isUrl(str)) {
sendToMain('uploadChoosedFiles', [{ path: str }])
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
} else {
$message.error($T('TIPS_DRAG_VALID_PICTURE_OR_URL'))
}
@@ -293,7 +293,7 @@ function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer)
const urlString = dataTransfer.getData(items[1].type)
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
if (urlMatch) {
sendToMain('uploadChoosedFiles', [
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
{
path: urlMatch[1]
}
@@ -321,7 +321,7 @@ function ipcSendFiles (files: FileList) {
}
sendFiles.push(obj)
})
sendToMain('uploadChoosedFiles', sendFiles)
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, sendFiles)
}
async function getPasteStyle () {
@@ -346,7 +346,7 @@ function handlePasteStyleChange (val: string | number | boolean | undefined) {
}
function uploadClipboardFiles () {
sendToMain('uploadClipboardFilesFromUploadPage')
sendRPC(IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE)
}
async function uploadURLFiles () {
@@ -361,7 +361,7 @@ async function uploadURLFiles () {
function handleInputBoxValue (val: string) {
if (val === '') return
if (isUrl(val)) {
sendToMain('uploadChoosedFiles', [{
sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{
path: val
}])
} else {
@@ -371,7 +371,7 @@ function handleInputBoxValue (val: string) {
async function getDefaultPicBed () {
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
picBed.value.forEach(item => {
picBedGlobal.value.forEach(item => {
if (item.type === currentPicBed) {
picBedName.value = item.name
}
@@ -379,20 +379,17 @@ async function getDefaultPicBed () {
picBedConfigName.value = await getConfig<string>(`picBed.${currentPicBed}._configName`) || ''
}
function getPicBeds (_event: Event, picBeds: IPicBedType[]) {
picBed.value = picBeds
getDefaultPicBed()
}
async function handleChangePicBed () {
sendToMain(SHOW_UPLOAD_PAGE_MENU)
sendRPC(IRPCActionType.SHOW_UPLOAD_PAGE_MENU)
}
</script>
<script lang="ts">
export default {
name: 'UploadPage'
}
</script>
<style lang='stylus'>
.view-title
display flex

View File

@@ -94,11 +94,10 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { ipcRenderer } from 'electron'
import { Edit, Delete, Plus } from '@element-plus/icons-vue'
import { onBeforeMount, ref } from 'vue'
import { useRouter, useRoute, onBeforeRouteUpdate } from 'vue-router'
import { saveConfig, triggerRPC } from '@/utils/dataSender'
import { saveConfig } from '@/utils/dataSender'
import { T as $T } from '@/i18n/index'
import { useStore } from '@/hooks/useStore'
@@ -106,6 +105,7 @@ import { PICBEDS_PAGE, UPLOADER_CONFIG_PAGE } from '@/router/config'
import { IRPCActionType } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { sendRPC, triggerRPC } from '@/utils/common'
const $router = useRouter()
const $route = useRoute()
@@ -116,8 +116,10 @@ const defaultConfigId = ref('')
const store = useStore()
async function selectItem (id: string) {
await triggerRPC<void>(IRPCActionType.SELECT_UPLOADER, type.value, id)
ipcRenderer.send('setTrayToolTip', `${type.value} ${curConfigList.value.find(item => item._id === id)?._configName || ''}`)
await triggerRPC<void>(IRPCActionType.UPLOADER_SELECT, type.value, id)
if (store?.state.defaultPicBed === type.value) {
sendRPC(IRPCActionType.TRAY_SET_TOOL_TIP, `${type.value} ${curConfigList.value.find(item => item._id === id)?._configName || ''}`)
}
defaultConfigId.value = id
}
@@ -135,7 +137,7 @@ onBeforeMount(() => {
})
async function getCurrentConfigList () {
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, type.value)
const configList = await triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, type.value)
curConfigList.value = configList?.configList ?? []
defaultConfigId.value = configList?.defaultId ?? ''
}
@@ -158,7 +160,7 @@ function formatTime (time: number): string {
}
async function deleteConfig (id: string) {
const res = await triggerRPC<IUploaderConfigItem | undefined>(IRPCActionType.DELETE_PICBED_CONFIG, type.value, id)
const res = await triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_DELETE_CONFIG, type.value, id)
if (!res) return
curConfigList.value = res.configList
defaultConfigId.value = res.defaultId
@@ -182,7 +184,7 @@ function setDefaultPicBed (type: string) {
store?.setDefaultPicBed(type)
const currentConfigName = curConfigList.value.find(item => item._id === defaultConfigId.value)?._configName
ipcRenderer.send('setTrayToolTip', `${type} ${currentConfigName || ''}`)
sendRPC(IRPCActionType.TRAY_SET_TOOL_TIP, `${type} ${currentConfigName || ''}`)
const successNotification = new Notification($T('SETTINGS_DEFAULT_PICBED'), {
body: $T('TIPS_SET_SUCCEED')
})

View File

@@ -99,21 +99,18 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import {
clipboard,
ipcRenderer,
IpcRendererEvent
clipboard
} from 'electron'
import { ElDropdown, ElMessage } from 'element-plus'
import { Link } from '@element-plus/icons-vue'
import { ref, onBeforeUnmount, onBeforeMount } from 'vue'
import { ref, onBeforeMount } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import ConfigForm from '@/components/ConfigForm.vue'
import { T as $T } from '@/i18n/index'
import { sendToMain } from '@/utils/common'
import { getConfig, triggerRPC } from '@/utils/dataSender'
import { sendRPC, triggerRPC } from '@/utils/common'
import { getConfig } from '@/utils/dataSender'
import { OPEN_URL } from '#/events/constants'
import { II18nLanguage, IRPCActionType } from '#/types/enum'
import { configPaths } from '#/utils/configPaths'
import { picBedManualUrlList } from '#/utils/static'
@@ -129,15 +126,14 @@ const $dropdown = ref<InstanceType<typeof ElDropdown> | null>(null)
type.value = $route.params.type as string
onBeforeMount(async () => {
sendToMain('getPicBedConfig', $route.params.type)
ipcRenderer.on('getPicBedConfig', getPicBeds)
await getPicBeds()
await getPicBedConfigList()
})
const handleConfirm = async () => {
const result = (await $configForm.value?.validate()) || false
if (result !== false) {
await triggerRPC<void>(IRPCActionType.UPDATE_UPLOADER_CONFIG, type.value, result?._id, result)
await triggerRPC<void>(IRPCActionType.UPLOADER_UPDATE_CONFIG, type.value, result?._id, result)
const successNotification = new Notification($T('SETTINGS_RESULT'), {
body: $T('TIPS_SET_SUCCEED')
})
@@ -156,8 +152,14 @@ function handleMouseLeave () {
$dropdown.value?.handleClose()
}
async function getPicBeds () {
const result = await triggerRPC<any>(IRPCActionType.PICBED_GET_PICBED_CONFIG, $route.params.type)
config.value = result.config
picBedName.value = result.name
}
async function getPicBedConfigList () {
const res = await triggerRPC<IUploaderConfigItem>(IRPCActionType.GET_PICBED_CONFIG_LIST, type.value) || undefined
const res = await triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, type.value) || undefined
const configList = res?.configList || []
picBedConfigList.value = configList.filter((item) => item._id !== $route.params.configId)
}
@@ -174,7 +176,7 @@ async function handleConfigImport (configItem: IUploaderConfigListItem) {
}
const handleReset = async () => {
await triggerRPC<void>(IRPCActionType.RESET_UPLOADER_CONFIG, type.value, $route.params.configId)
await triggerRPC<void>(IRPCActionType.UPLOADER_RESET_CONFIG, type.value, $route.params.configId)
const successNotification = new Notification($T('SETTINGS_RESULT'), {
body: $T('TIPS_RESET_SUCCEED')
})
@@ -188,7 +190,7 @@ async function handleNameClick () {
const lang = await getConfig(configPaths.settings.language) || II18nLanguage.ZH_CN
const url = picBedManualUrlList[lang === II18nLanguage.EN ? 'en' : 'zh_cn'][$route.params.type as string]
if (url) {
sendToMain(OPEN_URL, url)
sendRPC(IRPCActionType.OPEN_URL, url)
}
}
@@ -211,22 +213,14 @@ async function handleCopyApi () {
ElMessage.error('Copy failed')
}
}
function getPicBeds (_event: IpcRendererEvent, _config: IPicGoPluginConfig[], name: string) {
config.value = _config
picBedName.value = name
}
onBeforeUnmount(() => {
ipcRenderer.removeListener('getPicBedConfig', getPicBeds)
})
</script>
<script lang="ts">
export default {
name: 'PicbedsPage'
}
</script>
<style lang='stylus'>
#picbeds-page
height 100%

View File

@@ -32,34 +32,34 @@ export default createRouter({
{
path: 'manage-main-page',
name: config.MANAGE_MAIN_PAGE,
component: () => import(/* webpackChunkName: "ManageMainPage" */ '@/manage/pages/manageMain.vue'),
component: () => import(/* webpackChunkName: "ManageMainPage" */ '@/manage/pages/ManageMain.vue'),
children: [
{
path: '',
name: config.MANAGE_EMPTY_PAGE,
component: () => import(/* webpackChunkName: "ManageEmptyPage" */ '@/manage/pages/emptyPage.vue')
component: () => import(/* webpackChunkName: "ManageEmptyPage" */ '@/manage/pages/EmptyPage.vue')
},
{
path: 'manage-setting-page',
name: config.MANAGE_SETTING_PAGE,
component: () => import(/* webpackChunkName: "ManageSettingPage" */ '@/manage/pages/manageSetting.vue')
component: () => import(/* webpackChunkName: "ManageSettingPage" */ '@/manage/pages/ManageSetting.vue')
},
{
path: 'manage-bucket-page',
name: config.MANAGE_BUCKET_PAGE,
component: () => import(/* webpackChunkName: "ManageBucketPage" */ '@/manage/pages/bucketPage.vue')
component: () => import(/* webpackChunkName: "ManageBucketPage" */ '@/manage/pages/BucketPage.vue')
}
]
},
{
path: 'manage-login-page',
name: config.MANAGE_LOGIN_PAGE,
component: () => import(/* webpackChunkName: "ManageLoginPage" */ '@/manage/pages/logIn.vue')
component: () => import(/* webpackChunkName: "ManageLoginPage" */ '@/manage/pages/LogInPage.vue')
},
{
path: 'picbeds/:type/:configId?',
component: () => import(/* webpackChunkName: "Other" */ '@/pages/picbeds/index.vue'),
name: config.PICBEDS_PAGE
name: config.PICBEDS_PAGE,
component: () => import(/* webpackChunkName: "Other" */ '@/pages/picbeds/index.vue')
},
{
path: 'gallery',
@@ -71,8 +71,8 @@ export default createRouter({
},
{
path: 'setting',
component: () => import(/* webpackChunkName: "setting" */ '@/pages/PicGoSetting.vue'),
name: config.SETTING_PAGE
name: config.SETTING_PAGE,
component: () => import(/* webpackChunkName: "setting" */ '@/pages/PicGoSetting.vue')
},
{
path: 'plugin',

View File

@@ -1,15 +1,19 @@
import { ipcRenderer } from 'electron'
import { isReactive, isRef, toRaw, unref } from 'vue'
import { OPEN_URL } from '#/events/constants'
import { ILogType } from '#/types/enum'
import { RPC_ACTIONS, RPC_ACTIONS_INVOKE } from '#/events/constants'
import { IRPCActionType } from '#/types/enum'
const isDevelopment = process.env.NODE_ENV !== 'production'
export const handleTalkingDataEvent = (data: ITalkingDataOptions) => {
const { EventId, Label = '', MapKv = {} } = data
MapKv.from = window.location.href
window.TDAPP.onEvent(EventId, Label, MapKv)
try {
window.TDAPP.onEvent(EventId, Label, MapKv)
} catch (e) {
console.error(e)
}
if (isDevelopment) {
console.log('talkingData', data)
}
@@ -37,20 +41,26 @@ export function sendToMain (channel: string, ...args: any[]) {
ipcRenderer.send(channel, ...data)
}
/**
* send a rpc request & do not need to wait for the response
*
* or the response will be handled by other listener
*/
export function sendRPC (action: IRPCActionType, ...args: any[]): void {
const data = getRawData(args)
ipcRenderer.send(RPC_ACTIONS, action, data)
}
export function invokeToMain (channel: string, ...args: any[]) {
const data = getRawData(args)
return ipcRenderer.invoke(channel, ...data)
}
export const openURL = (url: string) => {
sendToMain(OPEN_URL, url)
}
export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => {
ipcRenderer.send('logDeleteMsg', msg || `Delete ${fileName} on ${type} success`, isSuccess ? ILogType.success : ILogType.error)
}
export const deleteFailedLog = (fileName: string, type: string, error: any) => {
deleteLog(fileName, type, false)
ipcRenderer.send('logDeleteMsg', error, ILogType.error)
/**
* trigger RPC action
* TODO: create an isolate rpc handler
*/
export async function triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<T | undefined> {
const data = getRawData(args)
return await ipcRenderer.invoke(RPC_ACTIONS_INVOKE, action, data)
}

View File

@@ -1,49 +1,21 @@
import { ipcRenderer, IpcRendererEvent } from 'electron'
import { v4 as uuid } from 'uuid'
import { ipcRenderer } from 'electron'
import { getRawData } from '@/utils/common'
import { sendRPC, triggerRPC } from '@/utils/common'
import { PICGO_SAVE_CONFIG, PICGO_GET_CONFIG, RPC_ACTIONS, PICGO_GET_CONFIG_SYNC } from '#/events/constants'
import { IRPCActionType } from '#/types/enum'
import { RPC_ACTIONS } from '#/events/constants'
import { IRPCActionType } from 'root/src/universal/types/enum'
export function saveConfig (config: IObj | string, value?: any) {
const configObject = typeof config === 'string' ? { [config]: value } : getRawData(config)
ipcRenderer.send(PICGO_SAVE_CONFIG, configObject)
const configObject = typeof config === 'string'
? { [config]: value }
: config
sendRPC(IRPCActionType.PICLIST_SAVE_CONFIG, configObject)
}
export async function getConfig<T> (key?: string): Promise<T | undefined> {
return await ipcRenderer.invoke(PICGO_GET_CONFIG, key)
return await triggerRPC<T>(IRPCActionType.PICLIST_GET_CONFIG, key)
}
export async function getConfigSync<T> (key?: string): Promise<T | undefined> {
return await ipcRenderer.sendSync(PICGO_GET_CONFIG_SYNC, key)
}
/**
* trigger RPC action
* TODO: create an isolate rpc handler
*/
export function triggerRPC<T> (action: IRPCActionType, ...args: any[]): Promise<T | null> {
return new Promise((resolve) => {
const callbackId = uuid()
const callback = (_event: IpcRendererEvent, data: T | null, returnActionType: IRPCActionType, returnCallbackId: string) => {
if (returnCallbackId === callbackId && returnActionType === action) {
resolve(data)
ipcRenderer.removeListener(RPC_ACTIONS, callback)
}
}
const data = getRawData(args)
ipcRenderer.on(RPC_ACTIONS, callback)
ipcRenderer.send(RPC_ACTIONS, action, data, callbackId)
})
}
/**
* send a rpc request & do not need to wait for the response
*
* or the response will be handled by other listener
*/
export function sendRPC (action: IRPCActionType, ...args: any[]): void {
const data = getRawData(args)
ipcRenderer.send(RPC_ACTIONS, action, data)
return await ipcRenderer.sendSync(RPC_ACTIONS, IRPCActionType.PICLIST_GET_CONFIG_SYNC, [key])
}

View File

@@ -1,63 +1,43 @@
import { ipcRenderer, IpcRendererEvent } from 'electron'
import { v4 as uuid } from 'uuid'
import { IObject, IResult, IGetResult, IFilter } from '@picgo/store/dist/types'
import { getRawData } from '@/utils/common'
import { triggerRPC } from '@/utils/common'
import {
PICGO_GET_DB,
PICGO_INSERT_DB,
PICGO_INSERT_MANY_DB,
PICGO_UPDATE_BY_ID_DB,
PICGO_GET_BY_ID_DB,
PICGO_REMOVE_BY_ID_DB
} from '#/events/constants'
import { IRPCActionType } from '#/types/enum'
import { IGalleryDB } from '#/types/extra-vue'
export class GalleryDB implements IGalleryDB {
async get<T> (filter?: IFilter): Promise<IGetResult<T>> {
const res = await this.#msgHandler<IGetResult<T>>(PICGO_GET_DB, filter)
async get<T> (filter?: IFilter): Promise<IGetResult<T> | undefined> {
const res = await this.#msgHandler<IGetResult<T>>(IRPCActionType.GALLERY_GET_DB, filter)
return res
}
async insert<T> (value: T): Promise<IResult<T>> {
const res = await this.#msgHandler<IResult<T>>(PICGO_INSERT_DB, value)
async insert<T> (value: T): Promise<IResult<T> | undefined> {
const res = await this.#msgHandler<IResult<T>>(IRPCActionType.GALLERY_INSERT_DB, value)
return res
}
async insertMany<T> (value: T[]): Promise<IResult<T>[]> {
const res = await this.#msgHandler<IResult<T>[]>(PICGO_INSERT_MANY_DB, value)
async insertMany<T> (value: T[]): Promise<IResult<T>[] | undefined> {
const res = await this.#msgHandler<IResult<T>[]>(IRPCActionType.GALLERY_INSERT_DB_BATCH, value)
return res
}
async updateById (id: string, value: IObject): Promise<boolean> {
const res = await this.#msgHandler<boolean>(PICGO_UPDATE_BY_ID_DB, id, value)
const res = await this.#msgHandler<boolean>(IRPCActionType.GALLERY_UPDATE_BY_ID_DB, id, value) || false
return res
}
async getById<T> (id: string): Promise<IResult<T> | undefined> {
const res = await this.#msgHandler<IResult<T> | undefined>(PICGO_GET_BY_ID_DB, id)
const res = await this.#msgHandler<IResult<T> | undefined>(IRPCActionType.GALLERY_GET_BY_ID_DB, id)
return res
}
async removeById (id: string): Promise<void> {
const res = await this.#msgHandler<void>(PICGO_REMOVE_BY_ID_DB, id)
const res = await this.#msgHandler<void>(IRPCActionType.GALLERY_REMOVE_BY_ID_DB, id)
return res
}
#msgHandler<T> (method: string, ...args: any[]): Promise<T> {
return new Promise((resolve) => {
const callbackId = uuid()
const callback = (_: IpcRendererEvent, data: T, returnCallbackId: string) => {
if (returnCallbackId === callbackId) {
resolve(data)
ipcRenderer.removeListener(method, callback)
}
}
const data = getRawData(args)
ipcRenderer.on(method, callback)
ipcRenderer.send(method, ...data, callbackId)
})
async #msgHandler<T> (method: IRPCActionType, ...args: any[]): Promise<T | undefined> {
return await triggerRPC<T>(method, ...args)
}
}

View File

@@ -0,0 +1,16 @@
import { ref } from 'vue'
import { triggerRPC } from '@/utils/common'
import { IRPCActionType } from '#/types/enum'
const osGlobal = ref<string>(process.platform)
const picBedGlobal = ref<IPicBedType[]>([])
async function updatePicBedGlobal () {
picBedGlobal.value = (await triggerRPC<IPicBedType[]>(IRPCActionType.MAIN_GET_PICBED))!
}
export {
osGlobal,
picBedGlobal,
updatePicBedGlobal
}

View File

@@ -1,18 +1,10 @@
import keycode from 'keycode'
const isSpecialKey = (key: string) => {
const keyArr = ['Shift', 'Control', 'Alt', 'Meta']
const isSpecialKey = (keyCode: number) => {
const keyArr = [
16, // Shift
17, // Ctrl
18, // Alt
91, // Left Meta
93 // Right Meta
]
return keyArr.includes(keyCode)
return keyArr.includes(key)
}
const keyDetect = (event: KeyboardEvent) => {
const keyBinding = (event: KeyboardEvent) => {
const meta = process.platform === 'darwin' ? 'Cmd' : 'Super'
const specialKey = {
Ctrl: event.ctrlKey,
@@ -29,10 +21,10 @@ const keyDetect = (event: KeyboardEvent) => {
}
}
if (!isSpecialKey(event.keyCode)) {
pressKey.push(keycode(event.keyCode).toUpperCase())
if (!isSpecialKey(event.key)) {
pressKey.push(event.key.toUpperCase())
}
return pressKey
}
export default keyDetect
export default keyBinding

View File

@@ -1,9 +1,8 @@
import { ipcRenderer } from 'electron'
import { ComponentOptions } from 'vue'
import bus from '@/utils/bus'
import { FORCE_UPDATE, GET_PICBEDS } from '#/events/constants'
import { FORCE_UPDATE } from '#/events/constants'
export const mainMixin: ComponentOptions = {
inject: ['forceUpdateTime'],
@@ -20,9 +19,6 @@ export const mainMixin: ComponentOptions = {
methods: {
forceUpdate () {
bus.emit(FORCE_UPDATE)
},
getPicBeds () {
ipcRenderer.send(GET_PICBEDS)
}
}
}

View File

@@ -3,41 +3,17 @@ export const SHOW_INPUT_BOX_RESPONSE = 'SHOW_INPUT_BOX_RESPONSE'
export const TOGGLE_SHORTKEY_MODIFIED_MODE = 'TOGGLE_SHORTKEY_MODIFIED_MODE'
export const TALKING_DATA_APPID = 'B743C16E2989419A9B02EDE9D1E6A530'
export const TALKING_DATA_EVENT = 'TALKING_DATA_EVENT'
export const PICGO_SAVE_CONFIG = 'PICGO_SAVE_CONFIG'
export const PICGO_GET_CONFIG = 'PICGO_GET_CONFIG'
export const PICGO_GET_CONFIG_SYNC = 'PICGO_GET_CONFIG_SYNC'
export const PICGO_GET_DB = 'PICGO_GET_DB'
export const PICGO_INSERT_DB = 'PICGO_INSERT_DB'
export const PICGO_INSERT_MANY_DB = 'PICGO_INSERT_MANY_DB'
export const PICGO_UPDATE_BY_ID_DB = 'PICGO_UPDATE_BY_ID_DB'
export const PICGO_GET_BY_ID_DB = 'PICGO_GET_BY_ID_DB'
export const PICGO_REMOVE_BY_ID_DB = 'PICGO_REMOVE_BY_ID_DB'
export const PICGO_OPEN_FILE = 'PICGO_OPEN_FILE'
export const PICGO_OPEN_DIRECTORY = 'PICGO_OPEN_DIRECTORY'
export const OPEN_DEVTOOLS = 'OPEN_DEVTOOLS'
export const SHOW_MINI_PAGE_MENU = 'SHOW_MINI_PAGE_MENU'
export const SHOW_MAIN_PAGE_MENU = 'SHOW_MAIN_PAGE_MENU'
export const SHOW_UPLOAD_PAGE_MENU = 'SHOW_UPLOAD_PAGE_MENU'
export const SHOW_PLUGIN_PAGE_MENU = 'SHOW_PLUGIN_PAGE_MENU'
export const MINIMIZE_WINDOW = 'MINIMIZE_WINDOW'
export const CLOSE_WINDOW = 'CLOSE_WINDOW'
export const OPEN_USER_STORE_FILE = 'OPEN_USER_STORE_FILE'
export const OPEN_URL = 'OPEN_URL'
export const HIDE_DOCK = 'HIDE_DOCK'
export const RELOAD_APP = 'RELOAD_APP'
export const PICGO_CONFIG_PLUGIN = 'PICGO_CONFIG_PLUGIN'
export const PICGO_HANDLE_PLUGIN_ING = 'PICGO_HANDLE_PLUGIN_ING'
export const PICGO_HANDLE_PLUGIN_DONE = 'PICGO_HANDLE_PLUGIN_DONE'
export const PICGO_TOGGLE_PLUGIN = 'PICGO_TOGGLE_PLUGIN'
export const PASTE_TEXT = 'PASTE_TEXT'
export const SET_MINI_WINDOW_POS = 'SET_MINI_WINDOW_POS'
export const RENAME_FILE_NAME = 'RENAME_FILE_NAME'
export const GET_RENAME_FILE_NAME = 'GET_RENAME_FILE_NAME'
export const SHOW_MAIN_PAGE_QRCODE = 'SHOW_MAIN_PAGE_QRCODE'
export const FORCE_UPDATE = 'FORCE_UPDATE'
export const OPEN_WINDOW = 'OPEN_WINDOW'
export const GET_PICBEDS = 'GET_PICBEDS'
export const RPC_ACTIONS = 'RPC_ACTIONS'
export const RPC_ACTIONS_INVOKE = 'RPC_ACTIONS_INVOKE'
// i18n
export const GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE'
export const GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST'

View File

@@ -12,6 +12,20 @@ export enum ILogType {
error = 'error'
}
export enum ICOREBuildInEvent {
UPLOAD_PROGRESS = 'uploadProgress',
FAILED = 'failed',
BEFORE_TRANSFORM = 'beforeTransform',
BEFORE_UPLOAD = 'beforeUpload',
AFTER_UPLOAD = 'afterUpload',
FINISHED = 'finished',
INSTALL = 'install',
UNINSTALL = 'uninstall',
UPDATE = 'update',
NOTIFICATION = 'notification',
REMOVE = 'remove',
}
export enum IPicGoHelperType {
afterUploadPlugins = 'afterUploadPlugins',
beforeTransformPlugins = 'beforeTransformPlugins',
@@ -59,28 +73,107 @@ export enum IRemoteNoticeTriggerCount {
/**
* renderer trigger action from main
*/
export enum IRPCActionType {
// config RPC
GET_PICBED_CONFIG_LIST = 'GET_PICBED_CONFIG_LIST',
DELETE_PICBED_CONFIG = 'DELETE_PICBED_CONFIG',
CHANGE_CURRENT_UPLOADER = 'CHANGE_CURRENT_UPLOADER',
SELECT_UPLOADER = 'SELECT_UPLOADER',
UPDATE_UPLOADER_CONFIG = 'UPDATE_UPLOADER_CONFIG',
RESET_UPLOADER_CONFIG = 'RESET_UPLOADER_CONFIG',
// version rpc
GET_LATEST_VERSION = 'GET_LATEST_VERSION',
export enum IRPCType {
INVOKE = 'INVOKE',
SEND = 'SEND'
}
export enum IRPCActionType {
// system rpc
RELOAD_APP = 'RELOAD_APP',
OPEN_URL = 'OPEN_URL',
OPEN_FILE = 'OPEN_FILE',
HIDE_DOCK = 'HIDE_DOCK',
GET_LANGUAGE_LIST = 'GET_LANGUAGE_LIST',
GET_CURRENT_LANGUAGE = 'GET_CURRENT_LANGUAGE',
SET_CURRENT_LANGUAGE = 'SET_CURRENT_LANGUAGE',
OPEN_WINDOW = 'OPEN_WINDOW',
OPEN_MINI_WINDOW = 'OPEN_MINI_WINDOW',
OPEN_MANUAL_WINDOW = 'OPEN_MANUAL_WINDOW',
CLOSE_WINDOW = 'CLOSE_WINDOW',
MINIMIZE_WINDOW = 'MINIMIZE_WINDOW',
SHOW_MINI_PAGE_MENU = 'SHOW_MINI_PAGE_MENU',
SHOW_MAIN_PAGE_MENU = 'SHOW_MAIN_PAGE_MENU',
SHOW_UPLOAD_PAGE_MENU = 'SHOW_UPLOAD_PAGE_MENU',
SHOW_PLUGIN_PAGE_MENU = 'SHOW_PLUGIN_PAGE_MENU',
SET_MINI_WINDOW_POS = 'SET_MINI_WINDOW_POS',
MINI_WINDOW_ON_TOP = 'MINI_WINDOW_ON_TOP',
MAIN_WINDOW_ON_TOP = 'MAIN_WINDOW_ON_TOP',
UPDATE_MINI_WINDOW_ICON = 'UPDATE_MINI_WINDOW_ICON',
REFRESH_SETTING_WINDOW = 'REFRESH_SETTING_WINDOW',
// picbed RPC
PICBED_GET_PICBED_CONFIG = 'PICBED_GET_PICBED_CONFIG',
PICBED_GET_CONFIG_LIST = 'PICBED_GET_CONFIG_LIST',
PICBED_DELETE_CONFIG = 'PICBED_DELETE_CONFIG',
UPLOADER_CHANGE_CURRENT = 'UPLOADER_CHANGE_CURRENT',
UPLOADER_SELECT = 'UPLOADER_SELECT',
UPLOADER_UPDATE_CONFIG = 'UPLOADER_UPDATE_CONFIG',
UPLOADER_RESET_CONFIG = 'UPLOADER_RESET_CONFIG',
// toolbox rpc
TOOLBOX_CHECK = 'TOOLBOX_CHECK',
TOOLBOX_CHECK_RES = 'TOOLBOX_CHECK_RES',
TOOLBOX_CHECK_FIX = 'TOOLBOX_CHECK_FIX',
// system rpc
RELOAD_APP = 'RELOAD_APP',
OPEN_FILE = 'OPEN_FILE',
COPY_TEXT = 'COPY_TEXT',
SHOW_DOCK_ICON = 'SHOW_DOCK_ICON',
// main app setting rpc
PICLIST_GET_CONFIG = 'PICLIST_GET_CONFIG',
PICLIST_GET_CONFIG_SYNC = 'PICLIST_GET_CONFIG_SYNC',
PICLIST_SAVE_CONFIG = 'PICLIST_SAVE_CONFIG',
PICLIST_OPEN_FILE = 'PICLIST_OPEN_FILE',
PICLIST_OPEN_DIRECTORY = 'PICLIST_OPEN_DIRECTORY',
PICLIST_AUTO_START = 'PICLIST_AUTO_START',
// shortkey setting rpc
SHORTKEY_UPDATE = 'SHORTKEY_UPDATE',
SHORTKEY_BIND_OR_UNBIND = 'SHORTKEY_BIND_OR_UNBIND',
SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE = 'SHORTKEY_TOGGLE_SHORTKEY_MODIFIED_MODE',
// configuration setting rpc
CONFIGURE_MIGRATE_FROM_PICGO = 'CONFIGURE_MIGRATE_FROM_PICGO',
CONFIGURE_UPLOAD_COMMON_CONFIG = 'CONFIGURE_UPLOAD_COMMON_CONFIG',
CONFIGURE_UPLOAD_MANAGE_CONFIG = 'CONFIGURE_UPLOAD_MANAGE_CONFIG',
CONFIGURE_UPLOAD_ALL_CONFIG = 'CONFIGURE_UPLOAD_ALL_CONFIG',
CONFIGURE_DOWNLOAD_COMMON_CONFIG = 'CONFIGURE_DOWNLOAD_COMMON_CONFIG',
CONFIGURE_DOWNLOAD_MANAGE_CONFIG = 'CONFIGURE_DOWNLOAD_MANAGE_CONFIG',
CONFIGURE_DOWNLOAD_ALL_CONFIG = 'CONFIGURE_DOWNLOAD_ALL_CONFIG',
// advanced setting rpc
ADVANCED_UPDATE_SERVER = 'ADVANCED_UPDATE_SERVER',
ADVANCED_STOP_WEB_SERVER = 'ADVANCED_STOP_WEB_SERVER',
ADVANCED_RESTART_WEB_SERVER = 'ADVANCED_RESTART_WEB_SERVER',
// upload and main page rpc
MAIN_GET_PICBED = 'MAIN_GET_PICBED',
UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE = 'UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE',
UPLOAD_CHOOSED_FILES = 'UPLOAD_CHOOSED_FILES',
// gallery rpc
GALLERY_PASTE_TEXT = 'GALLERY_PASTE_TEXT',
GALLERY_REMOVE_FILES = 'GALLERY_REMOVE_FILES',
GALLERY_GET_DB = 'GALLERY_GET_DB',
GALLERY_GET_BY_ID_DB = 'GALLERY_GET_BY_ID_DB',
GALLERY_UPDATE_BY_ID_DB = 'GALLERY_UPDATE_BY_ID_DB',
GALLERY_REMOVE_BY_ID_DB = 'GALLERY_REMOVE_BY_ID_DB',
GALLERY_INSERT_DB = 'GALLERY_INSERT_DB',
GALLERY_INSERT_DB_BATCH = 'GALLERY_INSERT_DB_BATCH',
GALLERY_LOG_DELETE_MSG = 'GALLERY_LOG_DELETE_MSG',
GALLERY_DELETE_SFTP_FILE = 'GALLERY_DELETE_SFTP_FILE',
GALLERY_DELETE_AWS_S3_FILE = 'GALLERY_DELETE_AWS_S3_FILE',
GALLERY_DELETE_DOGE_FILE = 'GALLERY_DELETE_DOGE_FILE',
GALLERY_DELETE_HUAWEI_OSS_FILE = 'GALLERY_DELETE_HUAWEI_OSS_FILE',
// plugin rpc
PLUGIN_GET_LIST = 'PLUGIN_GET_LIST',
PLUGIN_INSTALL = 'PLUGIN_INSTALL',
PLUGIN_IMPORT_LOCAL = 'PLUGIN_IMPORT_LOCAL',
PLUGIN_UPDATE_ALL = 'PLUGIN_UPDATE_ALL',
// tray rpc
TRAY_SET_TOOL_TIP = 'TRAY_SET_TOOL_TIP',
TRAY_GET_SHORT_URL = 'TRAY_GET_SHORT_URL',
TRAY_UPLOAD_CLIPBOARD_FILES = 'TRAY_UPLOAD_CLIPBOARD_FILES',
}
export enum IToolboxItemType {
@@ -97,6 +190,8 @@ export enum IToolboxItemCheckStatus {
ERROR = 'error',
}
// piclist setting
export enum ISartMode {
QUIET = 'quiet',
MINI = 'mini',
@@ -123,6 +218,8 @@ export enum commonTaskStatus {
paused = 'paused'
}
// manage task status
export enum uploadTaskSpecialStatus {
uploading = 'uploading',
uploaded = 'uploaded'

View File

@@ -1,9 +1,9 @@
import { IObject, IResult, IGetResult, IFilter } from '@picgo/store/dist/types'
interface IGalleryDB {
get<T>(filter?: IFilter): Promise<IGetResult<T>>
insert<T> (value: T): Promise<IResult<T>>
insertMany<T> (value: T[]): Promise<IResult<T>[]>
get<T>(filter?: IFilter): Promise<IGetResult<T> | undefined>
insert<T> (value: T): Promise<IResult<T> | undefined>
insertMany<T> (value: T[]): Promise<IResult<T>[] | undefined>
updateById (id: string, value: IObject): Promise<boolean>
getById<T> (id: string): Promise<IResult<T> | undefined>
removeById (id: string): Promise<void>
@@ -18,10 +18,9 @@ declare module 'vue' {
interface ComponentCustomProperties {
$$db: IGalleryDB
$T: typeof import('@/i18n/index').T
saveConfig(data: IObj | string, value?: any): void
getConfig<T>(key?: string): Promise<T | undefined>
setDefaultPicBed(picBed: string): void
triggerRPC<T> (action: import('#/types/enum').IRPCActionType, ...args: any[]): Promise<T | null>
triggerRPC<T> (action: import('#/types/enum').IRPCActionType, ...args: any[]): Promise<T | undefined>
sendRPC (action: import('#/types/enum').IRPCActionType, ...args: any[]): void
defaultPicBed: string
forceUpdate(): void
sendToMain(channel: string, ...args: any[]): void

View File

@@ -3,6 +3,7 @@ interface ILocales {
ABOUT: string
OPEN_MAIN_WINDOW: string
OPEN_MINI_WINDOW: string
HIDE_MINI_WINDOW: string
CHOOSE_DEFAULT_PICBED: string
OPEN_UPDATE_HELPER: string
RELOAD_APP: string

View File

@@ -1,13 +1,5 @@
type IGetUploaderConfigListArgs = [type: string]
type IDeleteUploaderConfigArgs = [type: string, id: string]
type ISelectUploaderConfigArgs = [type: string, id: string]
type IUpdateUploaderConfigArgs = [type: string, id: string, config: IStringKeyMap]
type IResetUploaderConfigArgs = [type: string, id: string]
type IGetLatestVersionArgs = [isCheckBetaVersion: boolean]
type IToolboxCheckArgs = [type: import('./enum').IToolboxItemType]
type IOpenFileArgs = [filePath: string]
type ICopyTextArgs = [text: string]
type IShowDockIconArgs = [visible: boolean]
interface IRPCServer {
@@ -16,12 +8,17 @@ interface IRPCServer {
use: (routes: IRPCRoutes) => void
}
type IRPCRoutes = Map<import('./enum').IRPCActionType, IRPCHandler<any>>
type IRPCRoutes = Map<import('./enum').IRPCActionType, {
handler: IRPCHandler<any>,
type: import('./enum').IRPCType
}>
type IRPCHandler<T> = (args: any[], event: import('electron').IpcMainEvent) => Promise<T>
type IIPCEvent = import('electron').IpcMainEvent | import('electron').IpcMainInvokeEvent
type IRPCHandler<T> = (event: IIPCEvent, args: any, ) => Promise<T>
interface IRPCRouter {
add<T>(action: import('./enum').IRPCActionType, handler: IRPCHandler<T>): IRPCRouter
add<T>(action: import('./enum').IRPCActionType, handler: IRPCHandler<T>, type: import('./enum').IRPCType):IRPCRouter
routes: () => IRPCRoutes
}

View File

@@ -1,6 +1,5 @@
interface ISettingForm {
updateHelper: boolean
showPicBedList: string[]
showUpdateTip: boolean
autoStart: boolean
rename: boolean
autoRename: boolean
@@ -10,7 +9,7 @@ interface ISettingForm {
autoCloseMiniWindow: boolean
autoCloseMainWindow: boolean
logLevel: string[]
autoCopyUrl: boolean
autoCopy: boolean
useBuiltinClipboard: boolean
logFileSizeLimit: number
deleteCloudFile: boolean
@@ -34,6 +33,10 @@ interface ISettingForm {
webServerHost: string
webServerPort: number
webServerPath: string
registry: string
proxy: string
mainWindowWidth: number
mainWindowHeight: number
}
interface IShortKeyMap {

View File

@@ -0,0 +1,16 @@
import { ipcRenderer } from 'electron'
import { ILogType, IRPCActionType } from '#/types/enum'
import { sendRPC } from '@/utils/common'
export const deleteLog = (fileName?: string, type?: string, isSuccess = true, msg?: string) => {
ipcRenderer
? sendRPC(IRPCActionType.GALLERY_LOG_DELETE_MSG, msg || `Delete ${fileName} on ${type} success`, isSuccess ? ILogType.success : ILogType.error)
: console.log(`Delete ${fileName} on ${type} success`)
}
export const deleteFailedLog = (fileName: string, type: string, error: any) => {
deleteLog(fileName, type, false)
ipcRenderer
? sendRPC(IRPCActionType.GALLERY_LOG_DELETE_MSG, error, ILogType.error)
: console.error(error)
}