diff --git a/packages/desktop/CHANGELOG.md b/packages/desktop/CHANGELOG.md index 2c076192..1634d5ad 100644 --- a/packages/desktop/CHANGELOG.md +++ b/packages/desktop/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/desktop +## 1.3.2 + +feat: 自动更新软件 + ## 1.3.1 feat: 增加录全屏 diff --git a/packages/desktop/electron-builder.json5 b/packages/desktop/electron-builder.json5 index f5f9f08e..2824aacb 100644 --- a/packages/desktop/electron-builder.json5 +++ b/packages/desktop/electron-builder.json5 @@ -2,7 +2,7 @@ * @see https://www.electron.build/configuration/configuration */ { - appId: 'com.electron.pear', + appId: 'com.electron.pear-rec', asar: false, productName: 'pear-rec', copyright: 'Copyright © 2023 ${author}', diff --git a/packages/desktop/electron/main/index.ts b/packages/desktop/electron/main/index.ts index f49132f9..d9aef56e 100644 --- a/packages/desktop/electron/main/index.ts +++ b/packages/desktop/electron/main/index.ts @@ -3,6 +3,7 @@ import { release } from 'node:os'; import * as mainWin from '../win/mainWin'; import { initTray } from './tray'; import './ipcMain'; +import { update } from './update'; import { registerFileProtocol } from './protocol'; import { registerGlobalShortcut, unregisterAllGlobalShortcut } from './globalShortcut'; import { initConfig } from './config'; @@ -39,7 +40,7 @@ if (!app.requestSingleInstanceLock()) { // process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true' async function createWindow() { - mainWin.createMainWin(); + mainWin.openMainWin(); } app.whenReady().then(() => { @@ -47,6 +48,8 @@ app.whenReady().then(() => { createWindow(); initTray(config.language); registerGlobalShortcut(); + // Apply electron-updater + update(); }); app.on('will-quit', () => { diff --git a/packages/desktop/electron/main/ipcMain.ts b/packages/desktop/electron/main/ipcMain.ts index c86edbcd..4d57af9c 100644 --- a/packages/desktop/electron/main/ipcMain.ts +++ b/packages/desktop/electron/main/ipcMain.ts @@ -92,9 +92,6 @@ function initIpcMain() { clipScreenWin.setIgnoreMouseEventsClipScreenWin(event, false); clipScreenWin.setIsPlayClipScreenWin(false); }); - ipcMain.handle('rs:close-record', () => { - return recorderScreenWin.getBoundsRecorderScreenWin(); - }); ipcMain.handle('rs:get-cursor-screen-point', () => { return recorderScreenWin.getCursorScreenPointRecorderScreenWin(); }); @@ -279,9 +276,6 @@ function initIpcMain() { const audios = await viewAudioWin.getAudios(audioUrl); return audios; }); - ipcMain.handle('va:set-historyAudio', async (e, audioUrl) => { - // store.setHistoryAudio(audioUrl); - }); // 设置 ipcMain.on('se:open-win', () => { settingWin.closeSettingWin(); @@ -289,7 +283,6 @@ function initIpcMain() { }); ipcMain.on('se:close-win', () => { settingWin.closeSettingWin(); - mainWin.showMainWin(); }); ipcMain.handle('se:set-filePath', async (e, filePath) => { let res = await dialog.showOpenDialog({ diff --git a/packages/desktop/electron/main/tray.ts b/packages/desktop/electron/main/tray.ts index acbdaf89..146dedd5 100644 --- a/packages/desktop/electron/main/tray.ts +++ b/packages/desktop/electron/main/tray.ts @@ -1,6 +1,6 @@ import { Menu, Tray, app, shell } from 'electron'; import { ICON } from './contract'; -import { showMainWin } from '../win/mainWin'; +import { openMainWin } from '../win/mainWin'; import { openShotScreenWin } from '../win/shotScreenWin'; import { openClipScreenWin } from '../win/clipScreenWin'; import { openRecorderAudioWin } from '../win/recorderAudioWin'; @@ -85,7 +85,7 @@ export function initTray(lng: string) { { label: t.home, click: () => { - showMainWin(); + openMainWin(); }, }, { @@ -120,7 +120,7 @@ export function initTray(lng: string) { appIcon.setToolTip('梨子REC'); appIcon.setContextMenu(contextMenu); appIcon.addListener('click', function () { - showMainWin(); + openMainWin(); }); return appIcon; } diff --git a/packages/desktop/electron/main/update.ts b/packages/desktop/electron/main/update.ts index 14ebfec7..57421e0d 100644 --- a/packages/desktop/electron/main/update.ts +++ b/packages/desktop/electron/main/update.ts @@ -1,33 +1,37 @@ import { app, ipcMain } from 'electron'; import { type ProgressInfo, type UpdateDownloadedEvent, autoUpdater } from 'electron-updater'; +import * as mainWin from '../win/mainWin'; -export function update(win: Electron.BrowserWindow) { +export function update() { // When set to false, the update download will be triggered through the API autoUpdater.autoDownload = false; autoUpdater.disableWebInstaller = false; autoUpdater.allowDowngrade = false; - // start check - autoUpdater.on('checking-for-update', function () {}); + autoUpdater.on('checking-for-update', function () { + console.log('Checking for update.'); + }); // update available autoUpdater.on('update-available', (arg) => { - win.webContents.send('update-can-available', { - update: true, - version: app.getVersion(), - newVersion: arg?.version, - }); + mainWin.sendEuUpdateCanAvailable(arg, true); + // win.webContents.send('eu:update-can-available', { + // update: true, + // version: app.getVersion(), + // newVersion: arg?.version, + // }); }); // update not available autoUpdater.on('update-not-available', (arg) => { - win.webContents.send('update-can-available', { - update: false, - version: app.getVersion(), - newVersion: arg?.version, - }); + mainWin.sendEuUpdateCanAvailable(arg, false); + // win.webContents.send('eu:update-can-available', { + // update: false, + // version: app.getVersion(), + // newVersion: arg?.version, + // }); }); // Checking for updates - ipcMain.handle('check-update', async () => { + ipcMain.handle('eu:check-update', async () => { if (!app.isPackaged) { const error = new Error('The update feature is only available after the package.'); return { message: error.message, error }; @@ -41,26 +45,26 @@ export function update(win: Electron.BrowserWindow) { }); // Start downloading and feedback on progress - ipcMain.handle('start-download', (event) => { + ipcMain.handle('eu:start-download', (event) => { startDownload( (error, progressInfo) => { if (error) { // feedback download error message - event.sender.send('update-error', { message: error.message, error }); + event.sender.send('eu:update-error', { message: error.message, error }); } else { // feedback update progress message - event.sender.send('download-progress', progressInfo); + event.sender.send('eu:download-progress', progressInfo); } }, () => { // feedback update downloaded message - event.sender.send('update-downloaded'); + event.sender.send('eu:update-downloaded'); }, ); }); // Install now - ipcMain.handle('quit-and-install', () => { + ipcMain.handle('eu:quit-and-install', () => { autoUpdater.quitAndInstall(false, true); }); } diff --git a/packages/desktop/electron/preload/electronAPI.ts b/packages/desktop/electron/preload/electronAPI.ts index 5a0e14c2..3100bdb0 100644 --- a/packages/desktop/electron/preload/electronAPI.ts +++ b/packages/desktop/electron/preload/electronAPI.ts @@ -84,8 +84,7 @@ contextBridge.exposeInMainWorld('electronAPI', { //vaWin sendVaOpenWin: (search?: any) => ipcRenderer.send('va:open-win', search), invokeVaGetAudios: (audioUrl: any) => ipcRenderer.invoke('va:get-audios', audioUrl), - sendVaSetHistoryAudio: (audioUrl: any) => ipcRenderer.send('va:set-historyAudio', audioUrl), - //seWin + //seWin 设置 sendSeOpenWin: () => ipcRenderer.send('se:open-win'), invokeSeGetUser: () => ipcRenderer.invoke('se:get-user'), invokeSeSetFilePath: (filePath: string) => ipcRenderer.invoke('se:set-filePath', filePath), @@ -94,16 +93,30 @@ contextBridge.exposeInMainWorld('electronAPI', { sendSeSetLanguage: (lng: string) => ipcRenderer.send('se:set-language', lng), invokeSeGetOpenAtLogin: () => ipcRenderer.invoke('se:get-openAtLogin'), - //re + //re 记录 sendReOpenWin: () => ipcRenderer.send('re:open-win'), - //pi + //pi 钉图 sendPiOpenWin: (search?: any) => ipcRenderer.send('pi:open-win', search), sendPiCloseWin: () => ipcRenderer.send('pi:close-win'), sendPiMinimizeWin: () => ipcRenderer.send('pi:minimize-win'), sendPiMaximizeWin: () => ipcRenderer.send('pi:maximize-win'), - // rfs + // rfs 全屏录屏 sendRfsOpenWin: () => ipcRenderer.send('rfs:open-win'), sendRfsCloseWin: () => ipcRenderer.send('rfs:close-win'), + + // Eu 自动更新 + handleEuUpdateCanAvailable: (callback: any) => + ipcRenderer.on('eu:update-can-available', callback), + handleEuUpdateeError: (callback: any) => ipcRenderer.on('eu:update-error', callback), + handleEuDownloadProgress: (callback: any) => ipcRenderer.on('eu:download-progress', callback), + handleEuUpdateDownloaded: (callback: any) => ipcRenderer.on('eu:update-downloaded', callback), + invokeEuQuitAndInstall: () => ipcRenderer.invoke('eu:quit-and-install'), + invokeEuStartDownload: () => ipcRenderer.invoke('eu:start-download'), + invokeEuCheckUpdate: () => ipcRenderer.invoke('eu:check-update'), + offEuUpdateCanAvailable: (callback: any) => ipcRenderer.on('eu:update-can-available', callback), + offEuUpdateeError: (callback: any) => ipcRenderer.on('eu:update-error', callback), + offEuDownloadProgress: (callback: any) => ipcRenderer.on('eu:download-progress', callback), + offEuUpdateDownloaded: (callback: any) => ipcRenderer.on('eu:update-downloaded', callback), }); diff --git a/packages/desktop/electron/win/mainWin.ts b/packages/desktop/electron/win/mainWin.ts index 8e9feb4a..a5433e25 100644 --- a/packages/desktop/electron/win/mainWin.ts +++ b/packages/desktop/electron/win/mainWin.ts @@ -1,6 +1,5 @@ import { app, screen, BrowserWindow, shell, ipcMain } from 'electron'; import { join } from 'node:path'; -// import { update } from '../main/update'; import { ICON, preload, url, WEB_URL } from '../main/contract'; const indexHtml = join(process.env.DIST, 'index.html'); @@ -53,9 +52,6 @@ const createMainWin = (): BrowserWindow => { return { action: 'deny' }; }); - // Apply electron-updater - // update(mainWin); - // mainWin.onbeforeunload = (e) => { // console.log('I do not want to be closed'); @@ -73,22 +69,17 @@ const createMainWin = (): BrowserWindow => { }; function closeMainWin() { - if (!mainWin?.isDestroyed()) { - mainWin!.close(); + if (mainWin && !mainWin?.isDestroyed()) { + mainWin?.close(); } mainWin = null; } function openMainWin() { - mainWin = createMainWin(); - mainWin!.show(); -} - -function showMainWin() { if (!mainWin || mainWin?.isDestroyed()) { mainWin = createMainWin(); } - mainWin!.show(); + mainWin?.show(); } function hideMainWin() { @@ -99,16 +90,10 @@ function minimizeMainWin() { mainWin!.minimize(); } -function maximizeMainWin() { - mainWin!.maximize(); -} - -function unmaximizeMainWin() { - mainWin!.unmaximize(); -} - function focusMainWin() { - if (mainWin) { + if (!mainWin || mainWin?.isDestroyed()) { + mainWin = createMainWin(); + } else { // Focus on the main window if the user tried to open another if (mainWin.isMinimized()) mainWin.restore(); if (!mainWin.isVisible()) mainWin.show(); @@ -116,13 +101,22 @@ function focusMainWin() { } } +function sendEuUpdateCanAvailable(arg, update) { + if (mainWin && !mainWin?.isDestroyed()) { + mainWin.webContents.send('eu:update-can-available', { + update: update, + version: app.getVersion(), + newVersion: arg?.version, + }); + } +} + export { - mainWin, createMainWin, closeMainWin, openMainWin, hideMainWin, - showMainWin, focusMainWin, minimizeMainWin, + sendEuUpdateCanAvailable, }; diff --git a/packages/desktop/package.json b/packages/desktop/package.json index b86bb5ab..d8623359 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@pear-rec/desktop", - "version": "1.3.0", + "version": "1.3.2", "main": "dist-electron/main/index.js", "description": "pear-rec", "author": { diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index 314f2e1e..f7e75385 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,9 @@ # @pear-rec/web +## 1.3.2 + +feat: 自动更新软件 + ## 1.3.1 feat: 增加录全屏 diff --git a/packages/web/package.json b/packages/web/package.json index 68abb70e..9abeb8ec 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@pear-rec/web", "private": true, - "version": "1.3.0", + "version": "1.3.2", "scripts": { "dev": "vite", "build": "rimraf dist && tsc && vite build", diff --git a/packages/web/src/components/home/HomeFooter.tsx b/packages/web/src/components/home/HomeFooter.tsx index aa7eb5a5..92b94966 100644 --- a/packages/web/src/components/home/HomeFooter.tsx +++ b/packages/web/src/components/home/HomeFooter.tsx @@ -2,8 +2,7 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SettingOutlined, HistoryOutlined } from '@ant-design/icons'; import { Button } from 'antd'; - -const logo = './imgs/icons/png/512x512.png'; +import UpdateElectron from '../update'; const HomeFooter = () => { const { t } = useTranslation(); @@ -33,6 +32,7 @@ const HomeFooter = () => { title={t('nav.record')} onClick={handleOpenRecordWin} /> + ); }; diff --git a/packages/web/src/components/update/index.tsx b/packages/web/src/components/update/index.tsx index 0c480220..b97f3c3b 100644 --- a/packages/web/src/components/update/index.tsx +++ b/packages/web/src/components/update/index.tsx @@ -1,146 +1,158 @@ -import { ipcRenderer } from "electron"; -import type { ProgressInfo } from "electron-updater"; -import { useCallback, useEffect, useState } from "react"; -import Modal from "@/components/update/Modal"; -import Progress from "@/components/update/Progress"; -import styles from "./update.module.scss"; +import type { ProgressInfo } from 'electron-updater'; +import { useCallback, useEffect, useState } from 'react'; +import { Badge, Avatar, Button } from 'antd'; +import { SyncOutlined } from '@ant-design/icons'; +import Modal from './Modal'; +import Progress from './Progress'; +import styles from './update.module.scss'; const Update = () => { - const [checking, setChecking] = useState(false); - const [updateAvailable, setUpdateAvailable] = useState(false); - const [versionInfo, setVersionInfo] = useState(); - const [updateError, setUpdateError] = useState(); - const [progressInfo, setProgressInfo] = useState>(); - const [modalOpen, setModalOpen] = useState(false); - const [modalBtn, setModalBtn] = useState<{ - cancelText?: string; - okText?: string; - onCancel?: () => void; - onOk?: () => void; - }>({ - onCancel: () => setModalOpen(false), - onOk: () => ipcRenderer.invoke("start-download"), - }); + const [checking, setChecking] = useState(false); + const [updateAvailable, setUpdateAvailable] = useState(false); + const [versionInfo, setVersionInfo] = useState(); + const [updateError, setUpdateError] = useState(); + const [progressInfo, setProgressInfo] = useState>(); + const [modalOpen, setModalOpen] = useState(false); + const [modalBtn, setModalBtn] = useState<{ + cancelText?: string; + okText?: string; + onCancel?: () => void; + onOk?: () => void; + }>({ + onCancel: () => setModalOpen(false), + // onOk: () => ipcRenderer.invoke('start-download'), + }); - const checkUpdate = async () => { - setChecking(true); - /** - * @type {import('electron-updater').UpdateCheckResult | null | { message: string, error: Error }} - */ - const result = await ipcRenderer.invoke("check-update"); - setProgressInfo({ percent: 0 }); - setChecking(false); - setModalOpen(true); - if (result?.error) { - setUpdateAvailable(false); - setUpdateError(result?.error); - } - }; + const checkUpdate = async () => { + setChecking(true); + /** + * @type {import('electron-updater').UpdateCheckResult | null | { message: string, error: Error }} + */ + // const result = await ipcRenderer.invoke('check-update'); + const result = await window.electronAPI?.invokeEuCheckUpdate(); + setProgressInfo({ percent: 0 }); + setChecking(false); + setModalOpen(true); + if (result?.error) { + setUpdateAvailable(false); + setUpdateError(result?.error); + } + }; - const onUpdateCanAvailable = useCallback( - (_event: Electron.IpcRendererEvent, arg1: VersionInfo) => { - setVersionInfo(arg1); - setUpdateError(undefined); - // Can be update - if (arg1.update) { - setModalBtn((state) => ({ - ...state, - cancelText: "Cancel", - okText: "Update", - onOk: () => ipcRenderer.invoke("start-download"), - })); - setUpdateAvailable(true); - } else { - setUpdateAvailable(false); - } - }, - [], - ); + const onUpdateCanAvailable = useCallback( + (_event: Electron.IpcRendererEvent, arg1: VersionInfo) => { + setVersionInfo(arg1); + setUpdateError(undefined); + // Can be update + console.log(arg1); + if (arg1.update) { + setModalBtn((state) => ({ + ...state, + cancelText: 'Cancel', + okText: 'Update', + // onOk: () => ipcRenderer.invoke('start-download'), + onOk: () => window.electronAPI?.invokeEuStartDownload(), + })); + setUpdateAvailable(true); + } else { + setUpdateAvailable(false); + } + }, + [], + ); - const onUpdateError = useCallback( - (_event: Electron.IpcRendererEvent, arg1: ErrorType) => { - setUpdateAvailable(false); - setUpdateError(arg1); - }, - [], - ); + const onUpdateError = useCallback((_event: Electron.IpcRendererEvent, arg1: ErrorType) => { + setUpdateAvailable(false); + setUpdateError(arg1); + }, []); - const onDownloadProgress = useCallback( - (_event: Electron.IpcRendererEvent, arg1: ProgressInfo) => { - setProgressInfo(arg1); - }, - [], - ); + const onDownloadProgress = useCallback( + (_event: Electron.IpcRendererEvent, arg1: ProgressInfo) => { + setProgressInfo(arg1); + }, + [], + ); - const onUpdateDownloaded = useCallback( - (_event: Electron.IpcRendererEvent, ...args: any[]) => { - setProgressInfo({ percent: 100 }); - setModalBtn((state) => ({ - ...state, - cancelText: "Later", - okText: "Install now", - onOk: () => ipcRenderer.invoke("quit-and-install"), - })); - }, - [], - ); + const onUpdateDownloaded = useCallback((_event: Electron.IpcRendererEvent, ...args: any[]) => { + setProgressInfo({ percent: 100 }); + setModalBtn((state) => ({ + ...state, + cancelText: 'Later', + okText: 'Install now', + onOk: () => window.electronAPI?.invokeEuQuitAndInstall(), + // onOk: () => ipcRenderer.invoke('quit-and-install'), + })); + }, []); - useEffect(() => { - // Get version information and whether to update - ipcRenderer.on("update-can-available", onUpdateCanAvailable); - ipcRenderer.on("update-error", onUpdateError); - ipcRenderer.on("download-progress", onDownloadProgress); - ipcRenderer.on("update-downloaded", onUpdateDownloaded); + useEffect(() => { + // Get version information and whether to update + window.electronAPI?.handleEuUpdateCanAvailable(onUpdateCanAvailable); + window.electronAPI?.handleEuUpdateeError(onUpdateError); + window.electronAPI?.handleEuDownloadProgress(onDownloadProgress); + window.electronAPI?.handleEuUpdateDownloaded(onUpdateDownloaded); - return () => { - ipcRenderer.off("update-can-available", onUpdateCanAvailable); - ipcRenderer.off("update-error", onUpdateError); - ipcRenderer.off("download-progress", onDownloadProgress); - ipcRenderer.off("update-downloaded", onUpdateDownloaded); - }; - }, []); + return () => { + window.electronAPI?.offEuUpdateCanAvailable(onUpdateCanAvailable); + window.electronAPI?.offEuUpdateeError(onUpdateError); + window.electronAPI?.offEuDownloadProgress(onDownloadProgress); + window.electronAPI?.offEuUpdateDownloaded(onUpdateDownloaded); + }; + // ipcRenderer.on('update-can-available', onUpdateCanAvailable); + // ipcRenderer.on('update-error', onUpdateError); + // ipcRenderer.on('download-progress', onDownloadProgress); + // ipcRenderer.on('update-downloaded', onUpdateDownloaded); - return ( - <> - -
- {updateError ? ( -
-

Error downloading the latest version.

-

{updateError.message}

-
- ) : updateAvailable ? ( -
-
The last version is: v{versionInfo?.newVersion}
-
- v{versionInfo?.version} -> v{versionInfo?.newVersion} -
-
-
Update progress:
-
- -
-
-
- ) : ( -
- {JSON.stringify(versionInfo ?? {}, null, 2)} -
- )} -
-
- - - ); + // return () => { + // ipcRenderer.off('update-can-available', onUpdateCanAvailable); + // ipcRenderer.off('update-error', onUpdateError); + // ipcRenderer.off('download-progress', onDownloadProgress); + // ipcRenderer.off('update-downloaded', onUpdateDownloaded); + // }; + }, []); + + return ( + <> + +
+ {updateError ? ( +
+

Error downloading the latest version.

+

{updateError.message}

+
+ ) : updateAvailable ? ( +
+
The last version is: v{versionInfo?.newVersion}
+
+ v{versionInfo?.version} -> v{versionInfo?.newVersion} +
+
+
Update progress:
+
+ +
+
+
+ ) : ( +
{JSON.stringify(versionInfo ?? {}, null, 2)}
+ )} +
+
+