mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 09:59:55 +08:00
feat(core): improve mobile perf (#15317)
#### PR Dependency Tree * **PR #15317** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Virtualized mobile navigation with shell navigation and interactive swipe menus; coordinated mobile back handling with interactive phases/state restoration. * Added shared auth request proxy and message-port based token handling across mobile and worker flows. * **Bug Fixes** * Hydrated remote worker error stacks for calls and observable errors. * Improved SQLite FTS/indexer and nbstore optional text handling; refined docs-search ref parsing and notification loading/retry. * **Refactor / UX** * Modal focus-preservation and pointer behavior updates; improved mobile menu controls and back gesture plugins. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -2,7 +2,9 @@ import { notify } from '@affine/component';
|
||||
import { getStoreManager } from '@affine/core/blocksuite/manager/store';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { AppFallback } from '@affine/core/mobile/components/app-fallback';
|
||||
import { MobileModalConfigProvider } from '@affine/core/mobile/components/mobile-modal-config-provider';
|
||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||
import { MobileBackCoordinator } from '@affine/core/mobile/modules/back-coordinator';
|
||||
import { VirtualKeyboardProvider } from '@affine/core/mobile/modules/virtual-keyboard';
|
||||
import { router } from '@affine/core/mobile/router';
|
||||
import { configureCommonModules } from '@affine/core/modules';
|
||||
@@ -32,6 +34,7 @@ import { WorkspacesService } from '@affine/core/modules/workspace';
|
||||
import { configureBrowserWorkspaceFlavours } from '@affine/core/modules/workspace-engine';
|
||||
import { getWorkerUrl } from '@affine/env/worker';
|
||||
import { I18n } from '@affine/i18n';
|
||||
import { serveAuthRequests } from '@affine/mobile-shared/auth/channel';
|
||||
import { StoreManagerClient } from '@affine/nbstore/worker/client';
|
||||
import { setTelemetryTransport } from '@affine/track';
|
||||
import { Container } from '@blocksuite/affine/global/di';
|
||||
@@ -44,7 +47,13 @@ import { App as CapacitorApp } from '@capacitor/app';
|
||||
import { Keyboard } from '@capacitor/keyboard';
|
||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||
import { InAppBrowser } from '@capgo/inappbrowser';
|
||||
import { Framework, FrameworkRoot, getCurrentStore } from '@toeverything/infra';
|
||||
import {
|
||||
Framework,
|
||||
FrameworkRoot,
|
||||
getCurrentStore,
|
||||
useLiveData,
|
||||
useService,
|
||||
} from '@toeverything/infra';
|
||||
import { OpClient } from '@toeverything/infra/op';
|
||||
import { AsyncCall } from 'async-call-rpc';
|
||||
import { useTheme } from 'next-themes';
|
||||
@@ -55,9 +64,14 @@ import { AffineTheme } from './plugins/affine-theme';
|
||||
import { AIButton } from './plugins/ai-button';
|
||||
import { Auth } from './plugins/auth';
|
||||
import { HashCash } from './plugins/hashcash';
|
||||
import { MobileBack } from './plugins/mobile-back';
|
||||
import { NbStoreNativeDBApis } from './plugins/nbstore';
|
||||
import { Preview } from './plugins/preview';
|
||||
import { clearEndpointSession, getValidAccessToken } from './proxy';
|
||||
import {
|
||||
authRequestProvider,
|
||||
clearEndpointSession,
|
||||
getValidAccessToken,
|
||||
} from './proxy';
|
||||
|
||||
const storeManagerClient = createStoreManagerClient();
|
||||
setTelemetryTransport(storeManagerClient.telemetry);
|
||||
@@ -409,19 +423,67 @@ const ThemeProvider = () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
const AndroidCapacitorApp = CapacitorApp as typeof CapacitorApp & {
|
||||
toggleBackButtonHandler(options: { enabled: boolean }): Promise<void>;
|
||||
};
|
||||
|
||||
const AndroidBackAdapter = () => {
|
||||
const coordinator = useService(MobileBackCoordinator);
|
||||
const canHandle = useLiveData(coordinator.canHandle$);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
AndroidCapacitorApp.toggleBackButtonHandler({ enabled: !canHandle }),
|
||||
MobileBack.setEnabled({ enabled: canHandle }),
|
||||
]).catch(console.error);
|
||||
}, [canHandle]);
|
||||
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
let remove = () => {};
|
||||
MobileBack.addListener('back', event => {
|
||||
const handled = coordinator.handleInteractivePhase(event.phase);
|
||||
if (event.phase === 'commit' && !handled) {
|
||||
coordinator.request('system-back');
|
||||
}
|
||||
})
|
||||
.then(handle => {
|
||||
if (disposed) handle.remove().catch(console.error);
|
||||
else
|
||||
remove = () => {
|
||||
handle.remove().catch(console.error);
|
||||
};
|
||||
})
|
||||
.catch(console.error);
|
||||
return () => {
|
||||
disposed = true;
|
||||
remove();
|
||||
Promise.all([
|
||||
AndroidCapacitorApp.toggleBackButtonHandler({ enabled: true }),
|
||||
MobileBack.setEnabled({ enabled: false }),
|
||||
]).catch(console.error);
|
||||
};
|
||||
}, [coordinator]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<Suspense>
|
||||
<FrameworkRoot framework={frameworkProvider}>
|
||||
<I18nProvider>
|
||||
<AffineContext store={getCurrentStore()}>
|
||||
<ThemeProvider />
|
||||
<RouterProvider
|
||||
fallbackElement={<AppFallback />}
|
||||
router={router}
|
||||
future={future}
|
||||
/>
|
||||
</AffineContext>
|
||||
<MobileModalConfigProvider>
|
||||
<AffineContext store={getCurrentStore()}>
|
||||
<ThemeProvider />
|
||||
<AndroidBackAdapter />
|
||||
<RouterProvider
|
||||
fallbackElement={<AppFallback />}
|
||||
router={router}
|
||||
future={future}
|
||||
/>
|
||||
</AffineContext>
|
||||
</MobileModalConfigProvider>
|
||||
</I18nProvider>
|
||||
</FrameworkRoot>
|
||||
</Suspense>
|
||||
@@ -460,22 +522,7 @@ function createStoreManagerClient() {
|
||||
|
||||
const { port1: authTokenChannelServer, port2: authTokenChannelClient } =
|
||||
new MessageChannel();
|
||||
authTokenChannelServer.addEventListener('message', event => {
|
||||
const { id, endpoint } = event.data as { id?: string; endpoint?: string };
|
||||
if (!id || !endpoint) return;
|
||||
getValidAccessToken(endpoint)
|
||||
.then(token => authTokenChannelServer.postMessage({ id, token }))
|
||||
.catch(error =>
|
||||
authTokenChannelServer.postMessage({
|
||||
id,
|
||||
error:
|
||||
typeof error === 'object' && error && 'code' in error
|
||||
? error.code
|
||||
: 'AUTH_SESSION_TEMPORARILY_UNAVAILABLE',
|
||||
})
|
||||
);
|
||||
});
|
||||
authTokenChannelServer.start();
|
||||
serveAuthRequests(authTokenChannelServer, authRequestProvider);
|
||||
worker.postMessage(
|
||||
{ type: 'auth-access-token-channel', port: authTokenChannelClient },
|
||||
[authTokenChannelClient]
|
||||
|
||||
Reference in New Issue
Block a user