feat(electron): create recording through tray (#10526)

- added tray menu for controlling recording status
- recording watcher for monitoring system audio input events
This commit is contained in:
pengx17
2025-03-18 04:12:30 +00:00
parent 05329e96c7
commit a016630a82
29 changed files with 1186 additions and 258 deletions

View File

@@ -1,3 +1,4 @@
import type { DocProps } from '@affine/core/blocksuite/initialization';
import { AffineContext } from '@affine/core/components/context';
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
import { AppContainer } from '@affine/core/desktop/components/app-container';
@@ -38,6 +39,8 @@ import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspac
import createEmotionCache from '@affine/core/utils/create-emotion-cache';
import { apis, events } from '@affine/electron-api';
import { StoreManagerClient } from '@affine/nbstore/worker/client';
import type { AttachmentBlockProps } from '@blocksuite/affine/model';
import { Text } from '@blocksuite/affine/store';
import { CacheProvider } from '@emotion/react';
import { Framework, FrameworkRoot, getCurrentStore } from '@toeverything/infra';
import { OpClient } from '@toeverything/infra/op';
@@ -174,32 +177,80 @@ events?.applicationMenu.openAboutPageInSettingModal(() => {
});
events?.applicationMenu.onNewPageAction(type => {
const currentWorkspace = getCurrentWorkspace();
if (!currentWorkspace) {
return;
}
const { workspace, dispose } = currentWorkspace;
const editorSettingService = frameworkProvider.get(EditorSettingService);
const docsService = workspace.scope.get(DocsService);
const editorSetting = editorSettingService.editorSetting;
const docProps = {
note: editorSetting.get('affine:note'),
};
apis?.ui
.isActiveTab()
.then(isActive => {
if (!isActive) {
return;
}
const currentWorkspace = getCurrentWorkspace();
if (!currentWorkspace) {
return;
}
const { workspace, dispose } = currentWorkspace;
const editorSettingService = frameworkProvider.get(EditorSettingService);
const docsService = workspace.scope.get(DocsService);
const editorSetting = editorSettingService.editorSetting;
const docProps = {
note: editorSetting.get('affine:note'),
};
const page = docsService.createDoc({ docProps, primaryMode: type });
workspace.scope.get(WorkbenchService).workbench.openDoc(page.id);
dispose();
})
.catch(err => {
console.error(err);
});
});
dispose();
events?.recording.onRecordingStatusChanged(status => {
(async () => {
if ((await apis?.ui.isActiveTab()) && status?.status === 'stopped') {
const currentWorkspace = getCurrentWorkspace();
if (!currentWorkspace) {
return;
}
const { workspace, dispose } = currentWorkspace;
const editorSettingService = frameworkProvider.get(EditorSettingService);
const docsService = workspace.scope.get(DocsService);
const editorSetting = editorSettingService.editorSetting;
const docProps: DocProps = {
note: editorSetting.get('affine:note'),
page: {
title: new Text(
'Recording ' +
(status.appGroup?.name ?? 'System Audio') +
' ' +
new Date(status.startTime).toISOString()
),
},
onStoreLoad: (doc, { noteId }) => {
(async () => {
const data = await apis?.recording.saveRecording(status.id);
if (!data) {
return;
}
const blob = new Blob([data], { type: 'audio/mp3' });
const blobId = await doc.workspace.blobSync.set(blob);
const attachmentProps: Partial<AttachmentBlockProps> = {
name: 'Recording',
size: blob.size,
type: 'audio/mp3',
sourceId: blobId,
embed: true,
};
doc.addBlock('affine:attachment', attachmentProps, noteId);
})().catch(console.error);
},
};
const page = docsService.createDoc({ docProps, primaryMode: 'page' });
workspace.scope.get(WorkbenchService).workbench.openDoc(page.id);
dispose();
}
})().catch(console.error);
});
events?.applicationMenu.onOpenJournal(() => {