🔨 Refactor: upload module && notification module

This commit is contained in:
PiEgg 2021-03-28 17:44:07 +08:00
parent f9d6191d5e
commit 3cad5f378d
11 changed files with 118 additions and 55 deletions

View File

@ -42,7 +42,7 @@
"keycode": "^2.2.0", "keycode": "^2.2.0",
"lodash-id": "^0.14.0", "lodash-id": "^0.14.0",
"lowdb": "^1.0.0", "lowdb": "^1.0.0",
"picgo": "^1.4.14", "picgo": "^1.4.18",
"qrcode.vue": "^1.7.0", "qrcode.vue": "^1.7.0",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-gallery": "^2.0.1", "vue-gallery": "^2.0.1",

View File

@ -21,7 +21,7 @@ let menu: Menu | null
let tray: Tray | null let tray: Tray | null
export function createContextMenu () { export function createContextMenu () {
const picBeds = getPicBeds() const picBeds = getPicBeds()
if (process.platform === "darwin" || process.platform === "win32") { if (process.platform === 'darwin' || process.platform === 'win32') {
const submenu = picBeds.filter(item => item.visible).map(item => { const submenu = picBeds.filter(item => item.visible).map(item => {
return { return {
label: item.name, label: item.name,
@ -89,8 +89,7 @@ export function createContextMenu() {
label: '退出' label: '退出'
} }
]) ])
} } else if (process.platform === 'linux') {
else if (process.platform === "linux") {
// TODO 图床选择功能 // TODO 图床选择功能
// 由于在Linux难以像在Mac和Windows上那样在点击时构造ContextMenu // 由于在Linux难以像在Mac和Windows上那样在点击时构造ContextMenu
// 暂时取消这个选单,避免引起和设置中启用的图床不一致 // 暂时取消这个选单,避免引起和设置中启用的图床不一致
@ -127,8 +126,8 @@ export function createContextMenu() {
title: 'PicGo', title: 'PicGo',
message: 'PicGo', message: 'PicGo',
buttons: ['Ok'], buttons: ['Ok'],
detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`, detail: `Version: ${pkg.version}\nAuthor: Molunerfinn\nGithub: https://github.com/Molunerfinn/PicGo`
}); })
} }
}, },
// @ts-ignore // @ts-ignore
@ -144,7 +143,7 @@ export function createTray() {
const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png` const menubarPic = process.platform === 'darwin' ? `${__static}/menubar.png` : `${__static}/menubar-nodarwin.png`
tray = new Tray(menubarPic) tray = new Tray(menubarPic)
// click事件在Mac和Windows上可以触发在Ubuntu上无法触发Unity不支持 // click事件在Mac和Windows上可以触发在Ubuntu上无法触发Unity不支持
if (process.platform === "darwin" || process.platform === "win32") { if (process.platform === 'darwin' || process.platform === 'win32') {
tray.on('right-click', () => { tray.on('right-click', () => {
if (windowManager.has(IWindowList.TRAY_WINDOW)) { if (windowManager.has(IWindowList.TRAY_WINDOW)) {
windowManager.get(IWindowList.TRAY_WINDOW)!.hide() windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
@ -220,10 +219,9 @@ export function createTray() {
} }
}) })
// toggleWindow() // toggleWindow()
} } else if (process.platform === 'linux') {
// click事件在Ubuntu上无法触发Unity不支持在Mac和Windows上可以触发 // click事件在Ubuntu上无法触发Unity不支持在Mac和Windows上可以触发
// 需要使用 setContextMenu 设置菜单 // 需要使用 setContextMenu 设置菜单
else if (process.platform === "linux") {
createContextMenu() createContextMenu()
tray!.setContextMenu(contextMenu) tray!.setContextMenu(contextMenu)
} }

View File

@ -1,5 +1,4 @@
import { import {
app,
Notification, Notification,
BrowserWindow, BrowserWindow,
ipcMain, ipcMain,
@ -11,9 +10,11 @@ import db from '#/datastore'
import windowManager from 'apis/app/window/windowManager' import windowManager from 'apis/app/window/windowManager'
import { IWindowList } from 'apis/app/window/constants' import { IWindowList } from 'apis/app/window/constants'
import util from 'util' import util from 'util'
import { IPicGo } from 'picgo/dist/src/types'
import { showNotification } from '~/main/utils/common'
const waitForShow = (webcontent: WebContents) => { const waitForShow = (webcontent: WebContents) => {
return new Promise((resolve, reject) => { return new Promise<void>((resolve, reject) => {
webcontent.on('did-finish-load', () => { webcontent.on('did-finish-load', () => {
resolve() resolve()
}) })
@ -37,6 +38,7 @@ const waitForRename = (window: BrowserWindow, id: number): Promise<string|null>
class Uploader { class Uploader {
private webContents: WebContents | null = null private webContents: WebContents | null = null
private uploading: boolean = false
constructor () { constructor () {
this.init() this.init()
} }
@ -60,7 +62,7 @@ class Uploader {
} }
}) })
picgo.helper.beforeUploadPlugins.register('renameFn', { picgo.helper.beforeUploadPlugins.register('renameFn', {
handle: async ctx => { handle: async (ctx: IPicGo) => {
const rename = db.get('settings.rename') const rename = db.get('settings.rename')
const autoRename = db.get('settings.autoRename') const autoRename = db.get('settings.autoRename')
if (autoRename || rename) { if (autoRename || rename) {
@ -91,10 +93,19 @@ class Uploader {
} }
upload (img?: IUploadOption): Promise<ImgInfo[]|false> { upload (img?: IUploadOption): Promise<ImgInfo[]|false> {
picgo.upload(img) if (this.uploading) {
showNotification({
title: '上传失败',
body: '前序上传还在继续,请稍后再试'
})
return Promise.resolve(false)
}
return new Promise((resolve) => { return new Promise((resolve) => {
try {
this.uploading = true
picgo.upload(img)
picgo.once('finished', ctx => { picgo.once('finished', ctx => {
this.uploading = false
if (ctx.output.every((item: ImgInfo) => item.imgUrl)) { if (ctx.output.every((item: ImgInfo) => item.imgUrl)) {
resolve(ctx.output) resolve(ctx.output)
} else { } else {
@ -103,16 +114,23 @@ class Uploader {
picgo.removeAllListeners('failed') picgo.removeAllListeners('failed')
}) })
picgo.once('failed', (e: Error) => { picgo.once('failed', (e: Error) => {
this.uploading = false
setTimeout(() => { setTimeout(() => {
const notification = new Notification({ showNotification({
title: '上传失败', title: '上传失败',
body: util.format(e.stack) body: util.format(e.stack),
clickToCopy: true
}) })
notification.show()
}, 500) }, 500)
picgo.removeAllListeners('finished') picgo.removeAllListeners('finished')
resolve(false) resolve(false)
}) })
} catch (e) {
this.uploading = false
picgo.removeAllListeners('failed')
picgo.removeAllListeners('finished')
resolve([])
}
}) })
} }
} }

View File

@ -27,7 +27,7 @@ class GuiApi implements IGuiApi {
return true return true
} }
settingWindow.show() settingWindow.show()
return new Promise((resolve, reject) => { return new Promise<void>((resolve, reject) => {
setTimeout(() => { setTimeout(() => {
resolve() resolve()
}, 1000) // TODO: a better way to wait page loaded. }, 1000) // TODO: a better way to wait page loaded.

View File

@ -12,6 +12,7 @@ import { IPicGoHelperType } from '#/types/enum'
import shortKeyHandler from '../apis/app/shortKey/shortKeyHandler' import shortKeyHandler from '../apis/app/shortKey/shortKeyHandler'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import { handleStreamlinePluginName } from '~/universal/utils/common' import { handleStreamlinePluginName } from '~/universal/utils/common'
import { IGuiMenuItem } from 'picgo/dist/src/types'
// eslint-disable-next-line // eslint-disable-next-line
const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
@ -62,12 +63,12 @@ const handleGetPluginList = () => {
const pluginList = picgo.pluginLoader.getFullList() const pluginList = picgo.pluginLoader.getFullList()
const list = [] const list = []
for (let i in pluginList) { for (let i in pluginList) {
const plugin = picgo.pluginLoader.getPlugin(pluginList[i]) const plugin = picgo.pluginLoader.getPlugin(pluginList[i])!
const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`) const pluginPath = path.join(STORE_PATH, `/node_modules/${pluginList[i]}`)
const pluginPKG = requireFunc(path.join(pluginPath, 'package.json')) const pluginPKG = requireFunc(path.join(pluginPath, 'package.json'))
const uploaderName = plugin.uploader || '' const uploaderName = plugin.uploader || ''
const transformerName = plugin.transformer || '' const transformerName = plugin.transformer || ''
let menu = [] let menu: IGuiMenuItem[] = []
if (plugin.guiMenu) { if (plugin.guiMenu) {
menu = plugin.guiMenu(picgo) menu = plugin.guiMenu(picgo)
} }
@ -200,7 +201,7 @@ const handlePluginActions = () => {
ipcMain.on('pluginActions', (event: IpcMainEvent, name: string, label: string) => { ipcMain.on('pluginActions', (event: IpcMainEvent, name: string, label: string) => {
const plugin = picgo.pluginLoader.getPlugin(name) const plugin = picgo.pluginLoader.getPlugin(name)
const guiApi = new GuiApi() const guiApi = new GuiApi()
if (plugin.guiMenu && plugin.guiMenu(picgo).length > 0) { if (plugin?.guiMenu?.(picgo)?.length) {
const menu: GuiMenuItem[] = plugin.guiMenu(picgo) const menu: GuiMenuItem[] = plugin.guiMenu(picgo)
menu.forEach(item => { menu.forEach(item => {
if (item.label === label) { if (item.label === label) {

View File

@ -1,8 +1,33 @@
import db from '#/datastore' import db from '#/datastore'
import { clipboard } from 'electron' import { clipboard, Notification } from 'electron'
export const handleCopyUrl = (str: string): void => { export const handleCopyUrl = (str: string): void => {
if (db.get('settings.autoCopy') !== false) { if (db.get('settings.autoCopy') !== false) {
clipboard.writeText(str) clipboard.writeText(str)
} }
} }
/**
* show notification
* @param options
*/
export const showNotification = (options: IPrivateShowNotificationOption = {
title: '',
body: '',
clickToCopy: false
}) => {
const notification = new Notification({
title: options.title,
body: options.body
})
const handleClick = () => {
if (options.clickToCopy) {
clipboard.writeText(options.body)
}
}
notification.once('click', handleClick)
notification.once('close', () => {
notification.removeListener('click', handleClick)
})
notification.show()
}

View File

@ -17,7 +17,7 @@ function dbChecker () {
if (!fs.existsSync(configFilePath)) { if (!fs.existsSync(configFilePath)) {
return return
} }
let configFile: string = '' let configFile: string = '{}'
let optionsTpl = { let optionsTpl = {
title: '注意', title: '注意',
body: '' body: ''

View File

@ -14,9 +14,8 @@ if (process.type !== 'renderer') {
if (!fs.pathExistsSync(STORE_PATH)) { if (!fs.pathExistsSync(STORE_PATH)) {
fs.mkdirpSync(STORE_PATH) fs.mkdirpSync(STORE_PATH)
} }
}
dbChecker() dbChecker()
}
class DB { class DB {
private db: Datastore.LowdbSync<Datastore.AdapterSync> private db: Datastore.LowdbSync<Datastore.AdapterSync>

View File

@ -196,6 +196,14 @@ type IUploadOption = string[]
interface IShowNotificationOption { interface IShowNotificationOption {
title: string title: string
body: string body: string
icon?: string | import('electron').NativeImage
}
interface IPrivateShowNotificationOption extends IShowNotificationOption{
/**
* click notification to copy the body
*/
clickToCopy?: boolean
} }
interface IShowMessageBoxOption { interface IShowMessageBoxOption {

View File

@ -2,7 +2,11 @@ const path = require('path')
function resolve (dir) { function resolve (dir) {
return path.join(__dirname, dir) return path.join(__dirname, dir)
} }
module.exports = {
const config = {
configureWebpack: {
devtool: 'nosources-source-map'
},
chainWebpack: config => { chainWebpack: config => {
config.resolve.alias config.resolve.alias
.set('@', resolve('src/renderer')) .set('@', resolve('src/renderer'))
@ -74,3 +78,13 @@ module.exports = {
} }
} }
} }
if (process.env.NODE_ENV === 'development') {
config.configureWebpack = {
devtool: 'eval-source-map'
}
}
module.exports = {
...config
}

View File

@ -8289,10 +8289,10 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
picgo@^1.4.14: picgo@^1.4.18:
version "1.4.14" version "1.4.18"
resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.4.14.tgz#312a1814d35eb8e326587d5cd99316b09a2882cc" resolved "https://registry.yarnpkg.com/picgo/-/picgo-1.4.18.tgz#5c8582c1b6b87e734ffc8596da6c5a1712cff0b0"
integrity sha512-r2i/Ox85xG5oskI4nemhdCU0SC/pxUzJ9np53qGC9qfQ2WumTLN5Ro09pDwFctxtI4Pl0jO03LAQ7hzVSX4rfA== integrity sha512-wUU76goKS5N5yjBKX9MszBcno1f0hTa+EdnuDknqLljtHe3ieBVZDbnu5IrYyqMge2u+tG8qx7G+PWvNjCPCHQ==
dependencies: dependencies:
chalk "^2.4.1" chalk "^2.4.1"
commander "^2.17.0" commander "^2.17.0"