diff --git a/packages/desktop/electron/main/constant.ts b/packages/desktop/electron/main/constant.ts index 2df76c3..7684346 100644 --- a/packages/desktop/electron/main/constant.ts +++ b/packages/desktop/electron/main/constant.ts @@ -20,6 +20,7 @@ export const DIST = path.join(DIST_ELECTRON, '../dist'); export const PUBLIC = url ? path.join(DIST_ELECTRON, '../public') : process.env.DIST; export const ICON = path.join(PUBLIC, './imgs/icons/png/32x32.png'); +export const ICONx2 = path.join(PUBLIC, './imgs/icons/png/64x64.png'); export const DOCS_PATH = path.join(homedir(), 'Documents'); @@ -125,7 +126,7 @@ export const WIN_CONFIG = { fullscreenable: false, // 窗口是否可以进入全屏状态 alwaysOnTop: true, // 窗口是否永远在别的窗口的上面 skipTaskbar: true, - // resizable: false, + resizable: false, }, recorderVideo: { html: path.join(process.env.DIST, 'recorderVideo.html'), diff --git a/packages/desktop/electron/main/index.ts b/packages/desktop/electron/main/index.ts index 77ea929..c12e585 100644 --- a/packages/desktop/electron/main/index.ts +++ b/packages/desktop/electron/main/index.ts @@ -11,6 +11,7 @@ import { protocolHandle, registerSchemesAsPrivileged } from './protocol'; import { initTray } from './tray'; import { update } from './update'; import { initApp } from './app'; +import { initNotification } from './notification'; initConfig(); initApp(); @@ -58,6 +59,7 @@ app.whenReady().then(() => { protocolHandle(); createWindow(); initTray(config.language); + initNotification(); update(); }); diff --git a/packages/desktop/electron/main/notification.ts b/packages/desktop/electron/main/notification.ts index 75f063e..fd31520 100644 --- a/packages/desktop/electron/main/notification.ts +++ b/packages/desktop/electron/main/notification.ts @@ -1,7 +1,14 @@ import { Notification } from 'electron'; -import { ICON } from './constant'; +import { ICONx2 } from './constant'; -export function showNotification(_options) { - const options = { icon: ICON, ..._options }; - new Notification(options).show(); +let notification = null; + +export function showNotification(options) { + notification.title = options.title; + notification.body = options.body; + notification.show(); +} + +export function initNotification() { + notification = new Notification({ icon: ICONx2 }); } diff --git a/packages/desktop/electron/win/recorderScreenWin.ts b/packages/desktop/electron/win/recorderScreenWin.ts index a6116f4..2c01573 100644 --- a/packages/desktop/electron/win/recorderScreenWin.ts +++ b/packages/desktop/electron/win/recorderScreenWin.ts @@ -28,12 +28,14 @@ function createRecorderScreenWin(search?: any): BrowserWindow { fullscreenable: WIN_CONFIG.recorderScreen.fullscreenable, // 窗口是否可以进入全屏状态 alwaysOnTop: WIN_CONFIG.recorderScreen.alwaysOnTop, // 窗口是否永远在别的窗口的上面 // skipTaskbar: WIN_CONFIG.recorderScreen.skipTaskbar, - // resizable: WIN_CONFIG.recorderScreen.resizable, + resizable: WIN_CONFIG.recorderScreen.resizable, webPreferences: { preload, }, }); + // recorderScreenWin.webContents.openDevTools(); + if (url) { recorderScreenWin.loadURL(WEB_URL + `recorderScreen.html?type=${search?.type || ''}`); } else { diff --git a/packages/web/src/components/recorderScreen/Camera.tsx b/packages/web/src/components/recorderScreen/Camera.tsx new file mode 100644 index 0000000..b857e29 --- /dev/null +++ b/packages/web/src/components/recorderScreen/Camera.tsx @@ -0,0 +1,21 @@ +import React, { useState, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { CameraOne } from '@icon-park/react'; + +const Camera = (props) => { + const { t } = useTranslation(); + + function handleCamera() { + if (window.electronAPI) { + window.electronAPI?.sendPvOpenWin(); + } + } + + return ( +
+ +
+ ); +}; + +export default Camera; diff --git a/packages/web/src/components/recorderScreen/FullScreen.tsx b/packages/web/src/components/recorderScreen/FullScreen.tsx index dcb31ec..00e693f 100644 --- a/packages/web/src/components/recorderScreen/FullScreen.tsx +++ b/packages/web/src/components/recorderScreen/FullScreen.tsx @@ -6,10 +6,12 @@ const FullScreen = (props) => { const { t } = useTranslation(); function handleFullRecordScreen() { - window.electronAPI?.sendRsCloseWin(); - window.electronAPI - ? window.electronAPI.sendRfsOpenWin() - : window.open('/recorderFullScreen.html'); + if (!props.isRecording) { + window.electronAPI?.sendRsCloseWin(); + window.electronAPI + ? window.electronAPI.sendRfsOpenWin() + : window.open('/recorderFullScreen.html'); + } } return ( diff --git a/packages/web/src/components/recorderScreen/MicMuteRecorder.tsx b/packages/web/src/components/recorderScreen/MicMuteRecorder.tsx index bfb0703..d436142 100644 --- a/packages/web/src/components/recorderScreen/MicMuteRecorder.tsx +++ b/packages/web/src/components/recorderScreen/MicMuteRecorder.tsx @@ -7,7 +7,9 @@ const MuteRecorder = (props) => { const [isMute, setIsMute] = useState(false); // 标记是否静音 function handleToggleMute() { - isMute ? unmuteRecording() : muteRecording(); + if (!props.isRecording) { + isMute ? unmuteRecording() : muteRecording(); + } } // 静音录制 diff --git a/packages/web/src/components/recorderScreen/ScreenRecorder.tsx b/packages/web/src/components/recorderScreen/ScreenRecorder.tsx index 8e162a1..c928a77 100644 --- a/packages/web/src/components/recorderScreen/ScreenRecorder.tsx +++ b/packages/web/src/components/recorderScreen/ScreenRecorder.tsx @@ -1,4 +1,4 @@ -import { CameraOutlined, ExclamationCircleFilled, DesktopOutlined } from '@ant-design/icons'; +import { ExclamationCircleFilled } from '@ant-design/icons'; import Timer from '@pear-rec/timer'; import useTimer from '@pear-rec/timer/src/useTimer'; import { mp4StreamToOPFSFile } from '@webav/av-cliper'; @@ -16,6 +16,7 @@ import MicMuteRecorder from './MicMuteRecorder'; import SoundMuteRecorder from './SoundMuteRecorder'; import FullScreen from './FullScreen'; import ShotScreen from './ShotScreen'; +import Camera from './Camera'; import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile, toBlobURL } from '@ffmpeg/util'; @@ -188,15 +189,40 @@ const ScreenRecorder = (props) => { mediaRecorder.current = new AVRecorder(recodeMS, { width: size.width, height: size.height }); } - function handleShotScreen() { - const { width, height } = props.size; + async function handleShotScreen() { + const { width, height } = window.isElectron + ? await window.electronAPI?.invokeRsGetBoundsClip() + : props.size; const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const context = canvas.getContext('2d'); context.drawImage(videoRef.current, 0, 0, canvas.width, canvas.height); - const url = canvas.toDataURL('image/png'); - saveAs(url, `pear-rec_${+new Date()}.png`); + canvas.toBlob((blob) => { + saveImg(blob); + }, 'image/png'); + } + + async function saveImg(blob) { + try { + const fileName = `pear-rec_${+new Date()}.png`; + const record = { + fileName: fileName, + fileData: blob, + fileType: 'ss', + userId: user.id, + createdAt: new Date(), + createdBy: user.id, + updatedAt: new Date(), + updatedBy: user.id, + }; + const recordId = await db.records.add(record); + if (recordId) { + window.electronAPI?.sendNotification({ title: '截图成功', body: '可以在历史中查看' }); + } + } catch (err) { + console.log('截图保存失败', err); + } } // 开始录制 @@ -316,7 +342,7 @@ const ScreenRecorder = (props) => {