refactor(electron): move electron-api to framework (#8601)

fix AF-1394
This commit is contained in:
pengx17
2024-10-30 09:16:20 +00:00
parent 50bae9c3e6
commit a791481ac8
81 changed files with 788 additions and 567 deletions

View File

@@ -1,10 +1,14 @@
import { Button } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { DesktopApiService } from '@affine/core/modules/desktop-api/service';
import { ThemeEditorService } from '@affine/core/modules/theme-editor';
import { UrlService } from '@affine/core/modules/url';
import { apis } from '@affine/electron-api';
import { DeleteIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import {
useLiveData,
useService,
useServiceOptional,
} from '@toeverything/infra';
import { cssVar } from '@toeverything/theme';
import { useCallback } from 'react';
@@ -12,14 +16,15 @@ export const ThemeEditorSetting = () => {
const themeEditor = useService(ThemeEditorService);
const modified = useLiveData(themeEditor.modified$);
const urlService = useService(UrlService);
const desktopApi = useServiceOptional(DesktopApiService);
const open = useCallback(() => {
if (BUILD_CONFIG.isElectron) {
apis?.ui.openThemeEditor().catch(console.error);
if (desktopApi) {
desktopApi.handler.ui.openThemeEditor().catch(console.error);
} else if (BUILD_CONFIG.isMobileWeb || BUILD_CONFIG.isWeb) {
urlService.openPopupWindow(location.origin + '/theme-editor');
}
}, [urlService]);
}, [desktopApi, urlService]);
return (
<SettingRow

View File

@@ -6,7 +6,7 @@ import {
Slider,
} from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
ConnectorMode,

View File

@@ -5,7 +5,7 @@ import {
type RadioItem,
} from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import { LayoutType, MindmapStyle } from '@blocksuite/affine/blocks';
import type { Doc } from '@blocksuite/affine/store';

View File

@@ -6,7 +6,7 @@ import {
Slider,
} from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
createEnumMap,

View File

@@ -1,6 +1,6 @@
import { MenuItem, MenuTrigger, Slider } from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import { LineColor, LineColorMap } from '@blocksuite/affine/blocks';
import type { Doc } from '@blocksuite/affine/store';

View File

@@ -6,7 +6,7 @@ import {
Slider,
} from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import type { EditorHost } from '@blocksuite/affine/block-std';
import type {

View File

@@ -1,6 +1,6 @@
import { Skeleton } from '@affine/component';
import type { EditorSettingSchema } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import type { EditorSettingSchema } from '@affine/core/modules/editor-setting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import type { EditorHost } from '@blocksuite/affine/block-std';
import { BlockStdScope } from '@blocksuite/affine/block-std';
import type { GfxPrimitiveElementModel } from '@blocksuite/affine/block-std/gfx';

View File

@@ -5,7 +5,7 @@ import {
type RadioItem,
} from '@affine/component';
import { SettingRow } from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import {
FontFamily,

View File

@@ -20,7 +20,7 @@ import {
EditorSettingService,
type FontFamily,
fontStyleOptions,
} from '@affine/core/modules/editor-settting';
} from '@affine/core/modules/editor-setting';
import {
type FontData,
SystemFontFamilyService,

View File

@@ -3,7 +3,7 @@ import {
SettingRow,
SettingWrapper,
} from '@affine/component/setting-components';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra';
import { useCallback } from 'react';

View File

@@ -3,9 +3,13 @@ import { SettingRow } from '@affine/component/setting-components';
import { Button } from '@affine/component/ui/button';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { useSystemOnline } from '@affine/core/components/hooks/use-system-online';
import { apis } from '@affine/electron-api';
import { DesktopApiService } from '@affine/core/modules/desktop-api/service';
import { useI18n } from '@affine/i18n';
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
import {
useService,
type Workspace,
type WorkspaceMetadata,
} from '@toeverything/infra';
import { useState } from 'react';
interface ExportPanelProps {
@@ -13,7 +17,7 @@ interface ExportPanelProps {
workspace: Workspace | null;
}
export const ExportPanel = ({
export const DesktopExportPanel = ({
workspaceMetadata,
workspace,
}: ExportPanelProps) => {
@@ -21,6 +25,7 @@ export const ExportPanel = ({
const t = useI18n();
const [saving, setSaving] = useState(false);
const isOnline = useSystemOnline();
const desktopApi = useService(DesktopApiService);
const onExport = useAsyncCallback(async () => {
if (saving || !workspace) {
@@ -33,7 +38,7 @@ export const ExportPanel = ({
await workspace.engine.blob.sync();
}
const result = await apis?.dialog.saveDBFileAs(workspaceId);
const result = await desktopApi.handler.dialog.saveDBFileAs(workspaceId);
if (result?.error) {
throw new Error(result.error);
} else if (!result?.canceled) {
@@ -44,7 +49,7 @@ export const ExportPanel = ({
} finally {
setSaving(false);
}
}, [isOnline, saving, t, workspace, workspaceId]);
}, [isOnline, saving, t, workspace, workspaceId, desktopApi]);
return (
<SettingRow name={t['Export']()} desc={t['Export Description']()}>

View File

@@ -13,7 +13,7 @@ import { useCallback } from 'react';
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
import { EnableCloudPanel } from './enable-cloud';
import { ExportPanel } from './export';
import { DesktopExportPanel } from './export';
import { LabelsPanel } from './labels';
import { MembersPanel } from './members';
import { ProfilePanel } from './profile';
@@ -71,7 +71,7 @@ export const WorkspaceSettingDetail = ({
<SharingPanel />
{BUILD_CONFIG.isElectron && (
<SettingWrapper title={t['Storage and Export']()}>
<ExportPanel
<DesktopExportPanel
workspace={workspace}
workspaceMetadata={workspaceMetadata}
/>

View File

@@ -5,7 +5,7 @@ import {
} from '@affine/component';
import { ServerConfigService } from '@affine/core/modules/cloud';
import { EditorService } from '@affine/core/modules/editor';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { JournalService } from '@affine/core/modules/journal';
import { toURLSearchParams } from '@affine/core/modules/navigation';
import { PeekViewService } from '@affine/core/modules/peek-view/services/peek-view';

View File

@@ -2,7 +2,7 @@ import {
AIEdgelessRootBlockSpec,
AIPageRootBlockSpec,
} from '@affine/core/blocksuite/presets/ai';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { mixpanel } from '@affine/track';
import {
ConfigExtension,

View File

@@ -8,7 +8,7 @@ import {
type useConfirmModal,
} from '@affine/component';
import type { EditorService } from '@affine/core/modules/editor';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { resolveLinkToDoc } from '@affine/core/modules/navigation';
import type { PeekViewService } from '@affine/core/modules/peek-view';
import {

View File

@@ -1,6 +1,6 @@
import { toast } from '@affine/component';
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { WorkbenchService } from '@affine/core/modules/workbench';
import type { DocMode } from '@blocksuite/affine/blocks';
import type { DocCollection } from '@blocksuite/affine/store';

View File

@@ -4,17 +4,17 @@ import {
} from '@affine/core/commands';
import { FindInPageService } from '@affine/core/modules/find-in-page/services/find-in-page';
import { track } from '@affine/track';
import { useService } from '@toeverything/infra';
import { useServiceOptional } from '@toeverything/infra';
import { useCallback, useEffect } from 'react';
export function useRegisterFindInPageCommands() {
const findInPage = useService(FindInPageService).findInPage;
const findInPage = useServiceOptional(FindInPageService)?.findInPage;
const toggleVisible = useCallback(() => {
// get the selected text in page
const selection = window.getSelection();
const selectedText = selection?.toString();
findInPage.toggleVisible(selectedText);
findInPage?.toggleVisible(selectedText);
}, [findInPage]);
useEffect(() => {

View File

@@ -1,3 +1,4 @@
// todo(@pengx17): remove jotai
import { UrlService } from '@affine/core/modules/url';
import type { UpdateMeta } from '@affine/electron-api';
import { apis, events } from '@affine/electron-api';

View File

@@ -1,4 +1,4 @@
import { EditorSettingService } from '@affine/core/modules/editor-settting';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { JournalService } from '@affine/core/modules/journal';
import { i18nTime } from '@affine/i18n';
import { track } from '@affine/track';

View File

@@ -1,9 +1,14 @@
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
import { DesktopApiService } from '@affine/core/modules/desktop-api/service';
import { I18nService } from '@affine/core/modules/i18n';
import { UrlService } from '@affine/core/modules/url';
import { useI18n } from '@affine/i18n';
import type { AffineEditorContainer } from '@blocksuite/affine/presets';
import { useService, WorkspaceService } from '@toeverything/infra';
import {
useService,
useServiceOptional,
WorkspaceService,
} from '@toeverything/infra';
import { useStore } from 'jotai';
import { useTheme } from 'next-themes';
import { useEffect } from 'react';
@@ -21,7 +26,7 @@ import {
} from '../../commands';
import { usePageHelper } from '../../components/blocksuite/block-suite-page-list/utils';
import { CreateWorkspaceDialogService } from '../../modules/create-workspace';
import { EditorSettingService } from '../../modules/editor-settting';
import { EditorSettingService } from '../../modules/editor-setting';
import { CMDKQuickSearchService } from '../../modules/quicksearch/services/cmdk';
import { useActiveBlocksuiteEditor } from './use-block-suite-editor';
import { useNavigateHelper } from './use-navigate-helper';
@@ -77,6 +82,9 @@ export function useRegisterWorkspaceCommands() {
const appSidebarService = useService(AppSidebarService);
const i18n = useService(I18nService).i18n;
const quitAndInstall =
useServiceOptional(DesktopApiService)?.handler.updater.quitAndInstall;
useEffect(() => {
const unsub = registerCMDKCommand(cmdkQuickSearchService, editor);
@@ -87,15 +95,20 @@ export function useRegisterWorkspaceCommands() {
// register AffineUpdatesCommands
useEffect(() => {
if (!quitAndInstall) {
return;
}
const unsub = registerAffineUpdatesCommands({
store,
t,
quitAndInstall,
});
return () => {
unsub();
};
}, [store, t]);
}, [quitAndInstall, store, t]);
// register AffineNavigationCommands
useEffect(() => {

View File

@@ -4,6 +4,7 @@ import {
resolveGlobalLoadingEventAtom,
} from '@affine/component/global-loading';
import { SidebarSwitch } from '@affine/core/modules/app-sidebar/views';
import { WorkspaceDesktopApiService } from '@affine/core/modules/desktop-api/service';
import { useI18n } from '@affine/i18n';
import { type DocMode, ZipTransformer } from '@blocksuite/affine/blocks';
import {
@@ -33,7 +34,7 @@ import { Map as YMap } from 'yjs';
import { AIProvider } from '../../blocksuite/presets/ai';
import { AppTabsHeader } from '../../modules/app-tabs-header';
import { EditorSettingService } from '../../modules/editor-settting';
import { EditorSettingService } from '../../modules/editor-setting';
import { NavigationButtons } from '../../modules/navigation';
import { useRegisterNavigationCommands } from '../../modules/navigation/view/use-register-navigation-commands';
import { QuickSearchContainer } from '../../modules/quicksearch';
@@ -179,6 +180,8 @@ export const WorkspaceLayoutProviders = ({ children }: PropsWithChildren) => {
};
const DesktopLayout = ({ children }: PropsWithChildren) => {
// is there a better way to make sure service is always available even if it's not explicitly used?
useService(WorkspaceDesktopApiService);
return (
<div className={styles.desktopAppViewContainer}>
<div className={styles.desktopTabsHeader}>

View File

@@ -11,7 +11,7 @@ import { EditorService } from '../modules/editor';
import {
EditorSettingService,
fontStyleOptions,
} from '../modules/editor-settting';
} from '../modules/editor-setting';
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
import * as styles from './page-detail-editor.css';

View File

@@ -1,10 +1,11 @@
import { NotificationCenter, notify } from '@affine/component';
import { events } from '@affine/electron-api';
import { DesktopApiService } from '@affine/core/modules/desktop-api/service';
import { WorkspaceFlavour } from '@affine/env/workspace';
import {
GlobalContextService,
useLiveData,
useService,
useServiceOptional,
WorkspaceService,
WorkspacesService,
} from '@toeverything/infra';
@@ -61,17 +62,16 @@ export const Setting = () => {
[setOpenSettingModalAtom]
);
const desktopApi = useServiceOptional(DesktopApiService);
useEffect(() => {
if (BUILD_CONFIG.isElectron) {
return events?.applicationMenu.openAboutPageInSettingModal(() =>
setOpenSettingModalAtom({
activeTab: 'about',
open: true,
})
);
}
return;
}, [setOpenSettingModalAtom]);
return desktopApi?.events?.applicationMenu.openAboutPageInSettingModal(() =>
setOpenSettingModalAtom({
activeTab: 'about',
open: true,
})
);
}, [desktopApi?.events?.applicationMenu, setOpenSettingModalAtom]);
if (!open) {
return null;

View File

@@ -1,37 +1,9 @@
import { apis, events } from '@affine/electron-api';
import { useAtomValue } from 'jotai';
import { atomWithObservable } from 'jotai/utils';
import { useCallback } from 'react';
import { combineLatest, map, Observable } from 'rxjs';
import { DesktopApiService } from '@affine/core/modules/desktop-api/service';
import { useService } from '@toeverything/infra';
import { useCallback, useEffect, useState } from 'react';
import * as style from './style.css';
const maximized$ = new Observable<boolean>(subscriber => {
subscriber.next(false);
if (events) {
return events.ui.onMaximized(res => {
subscriber.next(res);
});
}
return () => {};
});
const fullscreen$ = new Observable<boolean>(subscriber => {
subscriber.next(false);
if (events) {
return events.ui.onFullScreen(res => {
subscriber.next(res);
});
}
return () => {};
});
const maximizedAtom = atomWithObservable(() => {
return combineLatest([maximized$, fullscreen$]).pipe(
map(([maximized, fullscreen]) => maximized || fullscreen)
);
});
const minimizeSVG = (
<svg
width="10"
@@ -93,23 +65,34 @@ const unmaximizedSVG = (
);
export const WindowsAppControls = () => {
const handleMinimizeApp = useCallback(() => {
apis?.ui.handleMinimizeApp().catch(err => {
console.error(err);
});
}, []);
const handleMaximizeApp = useCallback(() => {
apis?.ui.handleMaximizeApp().catch(err => {
console.error(err);
});
}, []);
const handleCloseApp = useCallback(() => {
apis?.ui.handleCloseApp().catch(err => {
console.error(err);
});
}, []);
const desktopApi = useService(DesktopApiService);
const maximized = useAtomValue(maximizedAtom);
const handleMinimizeApp = useCallback(() => {
desktopApi.handler.ui.handleMinimizeApp().catch(err => {
console.error(err);
});
}, [desktopApi.handler.ui]);
const handleMaximizeApp = useCallback(() => {
desktopApi.handler.ui.handleMaximizeApp().catch(err => {
console.error(err);
});
}, [desktopApi.handler.ui]);
const handleCloseApp = useCallback(() => {
desktopApi.handler.ui.handleCloseApp().catch(err => {
console.error(err);
});
}, [desktopApi.handler.ui]);
const [maximized, setMaximized] = useState(false);
const [fullscreen, setFullscreen] = useState(false);
useEffect(() => {
return desktopApi.events.ui.onMaximized(setMaximized);
}, [desktopApi.events.ui]);
useEffect(() => {
return desktopApi.events.ui.onFullScreen(setFullscreen);
}, [desktopApi.events.ui]);
return (
<div
@@ -128,7 +111,7 @@ export const WindowsAppControls = () => {
className={style.windowAppControl}
onClick={handleMaximizeApp}
>
{maximized ? unmaximizedSVG : maximizeSVG}
{maximized || fullscreen ? unmaximizedSVG : maximizeSVG}
</button>
<button
data-type="close"

View File

@@ -21,7 +21,6 @@ import {
import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags';
import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk';
import { isNewTabTrigger } from '@affine/core/utils';
import { apis, events } from '@affine/electron-api';
import { useI18n } from '@affine/i18n';
import { track } from '@affine/track';
import type { Doc } from '@blocksuite/affine/store';
@@ -39,7 +38,7 @@ import {
} from '@toeverything/infra';
import { useSetAtom } from 'jotai';
import type { MouseEvent, ReactElement } from 'react';
import { useCallback, useEffect } from 'react';
import { useCallback } from 'react';
import { WorkbenchService } from '../../modules/workbench';
import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
@@ -105,25 +104,6 @@ export const RootAppSidebar = (): ReactElement => {
[pageHelper]
);
useEffect(() => {
if (BUILD_CONFIG.isElectron) {
return events?.applicationMenu.onNewPageAction(() => {
apis?.ui
.isActiveTab()
.then(isActive => {
if (!isActive) {
return;
}
onClickNewPage();
})
.catch(err => {
console.error(err);
});
});
}
return;
}, [onClickNewPage]);
const setOpenSettingModalAtom = useSetAtom(openSettingModalAtom);
const onOpenSettingModal = useCallback(() => {