PicList/src/main/lifeCycle/index.ts
2024-04-09 15:03:32 +08:00

314 lines
9.9 KiB
TypeScript

import './errorHandler'
import {
app,
globalShortcut,
protocol,
Notification,
dialog,
screen,
shell
} from 'electron'
import {
createProtocol
} from 'vue-cli-plugin-electron-builder/lib'
import beforeOpen from '~/main/utils/beforeOpen'
import ipcList from '~/main/events/ipcList'
import busEventList from '~/main/events/busEventList'
import { II18nLanguage, IRemoteNoticeTriggerHook, ISartMode, IWindowList } from '#/types/enum'
import windowManager from 'apis/app/window/windowManager'
import {
uploadChoosedFiles,
uploadClipboardFiles
} from 'apis/app/uploader/apis'
import {
createTray, setDockMenu
} from 'apis/app/system'
import server from '~/main/server/index'
import shortKeyHandler from 'apis/app/shortKey/shortKeyHandler'
import { getUploadFiles } from '~/main/utils/handleArgv'
import db from '~/main/apis/core/datastore'
import bus from '@core/bus'
import logger from 'apis/core/picgo/logger'
import picgo from 'apis/core/picgo'
import fixPath from './fixPath'
import { clearTempFolder } from '../manage/utils/common'
import { initI18n } from '~/main/utils/handleI18n'
import { remoteNoticeHandler } from 'apis/app/remoteNotice'
import { manageIpcList } from '../manage/events/ipcList'
import getManageApi from '../manage/Main'
import UpDownTaskQueue from '../manage/datastore/upDownTaskQueue'
import { T } from '~/main/i18n'
import { UpdateInfo, autoUpdater } from 'electron-updater'
import updateChecker from '../utils/updateChecker'
import clipboardPoll from '../utils/clipboardPoll'
import path from 'path'
import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static'
import fs from 'fs-extra'
import { startFileServer } from '../fileServer'
import webServer from '../server/webServer'
import axios from 'axios'
import { configPaths } from '~/universal/utils/configPaths'
const isDevelopment = process.env.NODE_ENV !== 'production'
const handleStartUpFiles = (argv: string[], cwd: string) => {
const files = getUploadFiles(argv, cwd, logger)
if (files === null || files.length > 0) { // 如果有文件列表作为参数,说明是命令行启动
if (files === null) {
logger.info('cli -> uploading file from clipboard')
uploadClipboardFiles()
} else {
logger.info('cli -> uploading files from cli', ...files.map(item => item.path))
const win = windowManager.getAvailableWindow()
uploadChoosedFiles(win.webContents, files)
}
return true
}
return false
}
autoUpdater.setFeedURL({
provider: 'generic',
url: 'https://release.piclist.cn/latest',
channel: 'latest'
})
autoUpdater.autoDownload = false
autoUpdater.on('update-available', async (info: UpdateInfo) => {
const lang = db.get(configPaths.settings.language) || II18nLanguage.ZH_CN
let updateLog = ''
try {
const url = lang === II18nLanguage.ZH_CN ? 'https://release.piclist.cn/currentVersion.md' : 'https://release.piclist.cn/currentVersion_en.md'
const res = await axios.get(url)
updateLog = res.data
} catch (e: any) {
logger.error(e)
}
dialog.showMessageBox({
type: 'info',
title: T('FIND_NEW_VERSION'),
buttons: ['Yes', 'Go to download page'],
message: T('TIPS_FIND_NEW_VERSION', {
v: info.version
}) + '\n\n' + updateLog,
checkboxLabel: T('NO_MORE_NOTICE'),
checkboxChecked: false
}).then((result) => {
if (result.response === 0) {
autoUpdater.downloadUpdate()
} else {
shell.openExternal('https://github.com/Kuingsmile/PicList/releases/latest')
}
db.set(configPaths.settings.showUpdateTip, !result.checkboxChecked)
}).catch((err) => {
logger.error(err)
})
})
autoUpdater.on('download-progress', (progressObj) => {
const percent = {
progress: progressObj.percent
}
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send('updateProgress', percent)
})
autoUpdater.on('update-downloaded', () => {
dialog.showMessageBox({
type: 'info',
title: T('UPDATE_DOWNLOADED'),
buttons: ['Yes', 'No'],
message: T('TIPS_UPDATE_DOWNLOADED')
}).then((result) => {
const window = windowManager.get(IWindowList.SETTING_WINDOW)!
window.webContents.send('updateProgress', { progress: 100 })
if (result.response === 0) {
autoUpdater.quitAndInstall()
}
}).catch((err) => {
logger.error(err)
})
})
autoUpdater.on('error', (err) => {
console.log(err)
})
class LifeCycle {
private async beforeReady () {
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
// fix the $PATH in macOS & linux
fixPath()
beforeOpen()
initI18n()
ipcList.listen()
getManageApi()
UpDownTaskQueue.getInstance()
manageIpcList.listen()
busEventList.listen()
}
private onReady () {
const readyFunction = async () => {
createProtocol('picgo')
windowManager.create(IWindowList.TRAY_WINDOW)
windowManager.create(IWindowList.SETTING_WINDOW)
const isAutoListenClipboard = db.get(configPaths.settings.isAutoListenClipboard) || false
const ClipboardWatcher = clipboardPoll
if (isAutoListenClipboard) {
db.set(configPaths.settings.isListeningClipboard, true)
ClipboardWatcher.startListening()
ClipboardWatcher.on('change', () => {
picgo.log.info('clipboard changed')
uploadClipboardFiles()
})
} else {
db.set(configPaths.settings.isListeningClipboard, false)
}
const isHideDock = db.get(configPaths.settings.isHideDock) || false
const startMode = db.get(configPaths.settings.startMode) || ISartMode.QUIET
if (process.platform === 'darwin') {
isHideDock ? app.dock.hide() : setDockMenu()
startMode !== ISartMode.NO_TRAY && createTray()
} else {
createTray()
}
db.set(configPaths.needReload, false)
updateChecker()
// 不需要阻塞
process.nextTick(() => {
shortKeyHandler.init()
})
server.startup()
startFileServer()
webServer.start()
if (process.env.NODE_ENV !== 'development') {
handleStartUpFiles(process.argv, process.cwd())
}
if (global.notificationList && global.notificationList?.length > 0) {
while (global.notificationList?.length) {
const option = global.notificationList.pop()
const notice = new Notification(option!)
notice.show()
}
}
await remoteNoticeHandler.init()
remoteNoticeHandler.triggerHook(IRemoteNoticeTriggerHook.APP_START)
if (startMode === ISartMode.MINI) {
windowManager.create(IWindowList.MINI_WINDOW)
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()
} else if (startMode === ISartMode.MAIN) {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
settingWindow.show()
settingWindow.focus()
}
const clipboardDir = path.join(picgo.baseDir, CLIPBOARD_IMAGE_FOLDER)
fs.ensureDir(clipboardDir)
}
app.whenReady().then(readyFunction)
}
private onRunning () {
app.on('second-instance', (event, commandLine, workingDirectory) => {
logger.info('detect second instance')
const result = handleStartUpFiles(commandLine, workingDirectory)
if (!result) {
if (windowManager.has(IWindowList.SETTING_WINDOW)) {
const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)!
if (settingWindow.isMinimized()) {
settingWindow.restore()
}
settingWindow.focus()
}
}
})
app.on('activate', () => {
createProtocol('picgo')
if (!windowManager.has(IWindowList.TRAY_WINDOW)) {
windowManager.create(IWindowList.TRAY_WINDOW)
}
if (!windowManager.has(IWindowList.SETTING_WINDOW)) {
windowManager.create(IWindowList.SETTING_WINDOW)
}
})
app.setLoginItemSettings({
openAtLogin: db.get(configPaths.settings.autoStart) || false
})
if (process.platform === 'win32') {
app.setAppUserModelId('com.kuingsmile.piclist')
}
if (process.env.XDG_CURRENT_DESKTOP && process.env.XDG_CURRENT_DESKTOP.includes('Unity')) {
process.env.XDG_CURRENT_DESKTOP = 'Unity'
}
}
private onQuit () {
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('will-quit', () => {
UpDownTaskQueue.getInstance().persist()
clearTempFolder()
globalShortcut.unregisterAll()
bus.removeAllListeners()
server.shutdown()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', data => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
}
async launchApp () {
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
await this.beforeReady()
this.onReady()
this.onRunning()
this.onQuit()
}
}
}
const bootstrap = new LifeCycle()
export {
bootstrap
}