From b369ee0cca74fbf72e45b5e2d1df33e182bdcd1f Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Mon, 25 Nov 2024 03:12:21 +0000 Subject: [PATCH] feat(mobile): disable swipe back gesture when there is no back in header (#8876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close AF-1663, AF-1756 - new global `ModalConfigContext` - new logic to judge whether inside modal - render `✕` for PageHeader back if inside modal - only enable `NavigationGesture` when there is `<` in PageHeader --- .../ios/App/App.xcodeproj/project.pbxproj | 13 ++++- .../ios/App/App/AFFiNEViewController.swift | 4 +- .../NavigationGesturePlugin.swift | 32 ++++++++++ packages/frontend/apps/ios/src/app.tsx | 20 +++++-- .../frontend/apps/ios/src/modal-config.tsx | 28 +++++++++ .../plugins/navigation-gesture/definitions.ts | 5 ++ .../src/plugins/navigation-gesture/index.ts | 9 +++ .../component/src/ui/modal/context.ts | 11 ++++ .../frontend/component/src/ui/modal/index.ts | 1 + .../frontend/component/src/ui/modal/modal.tsx | 26 ++++++++- .../components/mobile/config-modal/index.tsx | 2 +- .../core/src/components/mobile/index.ts | 1 - .../core/src/mobile/components/index.ts | 1 + .../components}/page-header/index.tsx | 23 +++++++- .../components}/page-header/styles.css.ts | 0 .../dialogs/selectors/generic-selector.tsx | 2 +- .../frontend/core/src/mobile/modules/index.ts | 2 + .../modules/navigation-gesture/index.ts | 13 +++++ .../providers/navigation-gesture.ts | 10 ++++ .../services/navigation-gesture.ts | 58 +++++++++++++++++++ .../workspace/detail/mobile-detail-page.tsx | 21 ++++--- .../views/all-docs/collection/detail.tsx | 2 +- .../views/all-docs/tag/detail-header.tsx | 2 +- 23 files changed, 260 insertions(+), 26 deletions(-) create mode 100644 packages/frontend/apps/ios/App/App/plugins/NavigationGesture/NavigationGesturePlugin.swift create mode 100644 packages/frontend/apps/ios/src/modal-config.tsx create mode 100644 packages/frontend/apps/ios/src/plugins/navigation-gesture/definitions.ts create mode 100644 packages/frontend/apps/ios/src/plugins/navigation-gesture/index.ts create mode 100644 packages/frontend/component/src/ui/modal/context.ts rename packages/frontend/core/src/{components/mobile => mobile/components}/page-header/index.tsx (76%) rename packages/frontend/core/src/{components/mobile => mobile/components}/page-header/styles.css.ts (100%) create mode 100644 packages/frontend/core/src/mobile/modules/navigation-gesture/index.ts create mode 100644 packages/frontend/core/src/mobile/modules/navigation-gesture/providers/navigation-gesture.ts create mode 100644 packages/frontend/core/src/mobile/modules/navigation-gesture/services/navigation-gesture.ts diff --git a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj index c7453edb67599..a7d6f5f240407 100644 --- a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj +++ b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 9D90BE2D2CCB9876006677DB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9D90BE222CCB9876006677DB /* Main.storyboard */; }; 9D90BE2E2CCB9876006677DB /* public in Resources */ = {isa = PBXBuildFile; fileRef = 9D90BE232CCB9876006677DB /* public */; }; C4C413792CBE705D00337889 /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; + E93B276C2CED92B1001409B8 /* NavigationGesturePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93B276B2CED92B1001409B8 /* NavigationGesturePlugin.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -35,6 +36,7 @@ 9D90BE232CCB9876006677DB /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; + E93B276B2CED92B1001409B8 /* NavigationGesturePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationGesturePlugin.swift; sourceTree = ""; }; FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -65,7 +67,6 @@ 504EC3051FED79650016851F /* Products */, 7F8756D8B27F46E3366F6CEA /* Pods */, 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */, - 9D6A85312CCF6D6B00DAB35F /* Recovered References */, ); indentWidth = 2; sourceTree = ""; @@ -101,6 +102,7 @@ 9D90BE1A2CCB9876006677DB /* plugins */ = { isa = PBXGroup; children = ( + E93B276A2CED9298001409B8 /* NavigationGesture */, 9D90BE192CCB9876006677DB /* Cookie */, ); path = plugins; @@ -122,6 +124,14 @@ path = App; sourceTree = ""; }; + E93B276A2CED9298001409B8 /* NavigationGesture */ = { + isa = PBXGroup; + children = ( + E93B276B2CED92B1001409B8 /* NavigationGesturePlugin.swift */, + ); + path = NavigationGesture; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -234,6 +244,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E93B276C2CED92B1001409B8 /* NavigationGesturePlugin.swift in Sources */, 9D90BE252CCB9876006677DB /* CookieManager.swift in Sources */, 9D90BE262CCB9876006677DB /* CookiePlugin.swift in Sources */, 9D6A85332CCF6DA700DAB35F /* HashcashPlugin.swift in Sources */, diff --git a/packages/frontend/apps/ios/App/App/AFFiNEViewController.swift b/packages/frontend/apps/ios/App/App/AFFiNEViewController.swift index bddedfec4b8a4..c95e3866f565f 100644 --- a/packages/frontend/apps/ios/App/App/AFFiNEViewController.swift +++ b/packages/frontend/apps/ios/App/App/AFFiNEViewController.swift @@ -5,11 +5,13 @@ class AFFiNEViewController: CAPBridgeViewController { override func viewDidLoad() { super.viewDidLoad() - webView?.allowsBackForwardNavigationGestures = true + // disable by default, enable manually when there is a "back" button in page-header + webView?.allowsBackForwardNavigationGestures = false } override func capacitorDidLoad() { bridge?.registerPluginInstance(CookiePlugin()) bridge?.registerPluginInstance(HashcashPlugin()) + bridge?.registerPluginInstance(NavigationGesturePlugin()) } } diff --git a/packages/frontend/apps/ios/App/App/plugins/NavigationGesture/NavigationGesturePlugin.swift b/packages/frontend/apps/ios/App/App/plugins/NavigationGesture/NavigationGesturePlugin.swift new file mode 100644 index 0000000000000..045fce128862e --- /dev/null +++ b/packages/frontend/apps/ios/App/App/plugins/NavigationGesture/NavigationGesturePlugin.swift @@ -0,0 +1,32 @@ +import Foundation +import Capacitor + +@objc(NavigationGesturePlugin) +public class NavigationGesturePlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "NavigationGesturePlugin" + public let jsName = "NavigationGesture" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "isEnabled", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "enable", returnType: CAPPluginReturnPromise), + CAPPluginMethod(name: "disable", returnType: CAPPluginReturnPromise) + ] + + @objc func isEnabled(_ call: CAPPluginCall) { + let enabled = self.bridge?.webView?.allowsBackForwardNavigationGestures ?? true + call.resolve(["value": enabled]) + } + + @objc func enable(_ call: CAPPluginCall) { + DispatchQueue.main.sync { + self.bridge?.webView?.allowsBackForwardNavigationGestures = true + call.resolve([:]) + } + } + + @objc func disable(_ call: CAPPluginCall) { + DispatchQueue.main.sync { + self.bridge?.webView?.allowsBackForwardNavigationGestures = false + call.resolve([:]) + } + } +} diff --git a/packages/frontend/apps/ios/src/app.tsx b/packages/frontend/apps/ios/src/app.tsx index 6cab81b479442..c594817f9b912 100644 --- a/packages/frontend/apps/ios/src/app.tsx +++ b/packages/frontend/apps/ios/src/app.tsx @@ -1,6 +1,7 @@ import { AffineContext } from '@affine/core/components/context'; import { AppFallback } from '@affine/core/mobile/components/app-fallback'; import { configureMobileModules } from '@affine/core/mobile/modules'; +import { NavigationGestureProvider } from '@affine/core/mobile/modules/navigation-gesture'; import { VirtualKeyboardProvider } from '@affine/core/mobile/modules/virtual-keyboard'; import { router } from '@affine/core/mobile/router'; import { configureCommonModules } from '@affine/core/modules'; @@ -32,8 +33,10 @@ import { Suspense } from 'react'; import { RouterProvider } from 'react-router-dom'; import { configureFetchProvider } from './fetch'; +import { ModalConfigProvider } from './modal-config'; import { Cookie } from './plugins/cookie'; import { Hashcash } from './plugins/hashcash'; +import { NavigationGesture } from './plugins/navigation-gesture'; const future = { v7_startTransition: true, @@ -86,6 +89,11 @@ framework.impl(VirtualKeyboardProvider, { Keyboard.removeAllListeners(); }, }); +framework.impl(NavigationGestureProvider, { + isEnabled: () => NavigationGesture.isEnabled(), + enable: () => NavigationGesture.enable(), + disable: () => NavigationGesture.disable(), +}); const frameworkProvider = framework.provider(); // setup application lifecycle events, and emit application start event @@ -132,11 +140,13 @@ export function App() { - } - router={router} - future={future} - /> + + } + router={router} + future={future} + /> + diff --git a/packages/frontend/apps/ios/src/modal-config.tsx b/packages/frontend/apps/ios/src/modal-config.tsx new file mode 100644 index 0000000000000..57acb06653cec --- /dev/null +++ b/packages/frontend/apps/ios/src/modal-config.tsx @@ -0,0 +1,28 @@ +import { ModalConfigContext } from '@affine/component'; +import { NavigationGestureService } from '@affine/core/mobile/modules/navigation-gesture'; +import { useService } from '@toeverything/infra'; +import { type PropsWithChildren, useCallback } from 'react'; + +export const ModalConfigProvider = ({ children }: PropsWithChildren) => { + const navigationGesture = useService(NavigationGestureService); + + const onOpenChange = useCallback( + (open: boolean) => { + const prev = navigationGesture.enabled$.value; + if (open && !prev) { + navigationGesture.setEnabled(false); + return () => { + navigationGesture.setEnabled(prev); + }; + } + return; + }, + [navigationGesture] + ); + + return ( + + {children} + + ); +}; diff --git a/packages/frontend/apps/ios/src/plugins/navigation-gesture/definitions.ts b/packages/frontend/apps/ios/src/plugins/navigation-gesture/definitions.ts new file mode 100644 index 0000000000000..c65018514ea6d --- /dev/null +++ b/packages/frontend/apps/ios/src/plugins/navigation-gesture/definitions.ts @@ -0,0 +1,5 @@ +export interface NavigationGesturePlugin { + isEnabled: () => Promise; + enable: () => Promise; + disable: () => Promise; +} diff --git a/packages/frontend/apps/ios/src/plugins/navigation-gesture/index.ts b/packages/frontend/apps/ios/src/plugins/navigation-gesture/index.ts new file mode 100644 index 0000000000000..9215c1373219d --- /dev/null +++ b/packages/frontend/apps/ios/src/plugins/navigation-gesture/index.ts @@ -0,0 +1,9 @@ +import { registerPlugin } from '@capacitor/core'; + +import type { NavigationGesturePlugin } from './definitions'; + +const NavigationGesture = + registerPlugin('NavigationGesture'); + +export * from './definitions'; +export { NavigationGesture }; diff --git a/packages/frontend/component/src/ui/modal/context.ts b/packages/frontend/component/src/ui/modal/context.ts new file mode 100644 index 0000000000000..f40370d4ed5e3 --- /dev/null +++ b/packages/frontend/component/src/ui/modal/context.ts @@ -0,0 +1,11 @@ +import { createContext } from 'react'; + +export interface ModalConfig { + /** + * add global callback for modal open/close + */ + onOpenChange?: (open: boolean) => void; +} +export const ModalConfigContext = createContext({}); + +export const InsideModalContext = createContext(0); diff --git a/packages/frontend/component/src/ui/modal/index.ts b/packages/frontend/component/src/ui/modal/index.ts index be56583f7878c..790b395190c97 100644 --- a/packages/frontend/component/src/ui/modal/index.ts +++ b/packages/frontend/component/src/ui/modal/index.ts @@ -1,4 +1,5 @@ export * from './confirm-modal'; +export * from './context'; export * from './modal'; export * from './overlay-modal'; export * from './prompt-modal'; diff --git a/packages/frontend/component/src/ui/modal/modal.tsx b/packages/frontend/component/src/ui/modal/modal.tsx index 50beae578c045..cc6a2ab9d2caa 100644 --- a/packages/frontend/component/src/ui/modal/modal.tsx +++ b/packages/frontend/component/src/ui/modal/modal.tsx @@ -10,12 +10,19 @@ import * as VisuallyHidden from '@radix-ui/react-visually-hidden'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import clsx from 'clsx'; import type { CSSProperties } from 'react'; -import { forwardRef, useCallback, useEffect, useState } from 'react'; +import { + forwardRef, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; import { startScopedViewTransition } from '../../utils'; import type { IconButtonProps } from '../button'; import { IconButton } from '../button'; import { SafeArea } from '../safe-area'; +import { InsideModalContext, ModalConfigContext } from './context'; import * as styles from './styles.css'; export interface ModalProps extends DialogProps { @@ -123,6 +130,7 @@ function createContainer() { export const ModalInner = forwardRef( (props, ref) => { + const modalConfig = useContext(ModalConfigContext); const { modal, portalOptions, @@ -164,6 +172,10 @@ export const ModalInner = forwardRef( null ); + useEffect(() => { + modalConfig.onOpenChange?.(open ?? false); + }, [modalConfig, open]); + useEffect(() => { if (open) { const container = createContainer(); @@ -304,10 +316,20 @@ export const ModalInner = forwardRef( ModalInner.displayName = 'ModalInner'; export const Modal = forwardRef((props, ref) => { + const insideModal = useContext(InsideModalContext); if (!props.open) { return; } - return ; + return ( + + + + ); }); Modal.displayName = 'Modal'; + +export const useIsInsideModal = () => { + const context = useContext(InsideModalContext); + return context > 0; +}; diff --git a/packages/frontend/core/src/components/mobile/config-modal/index.tsx b/packages/frontend/core/src/components/mobile/config-modal/index.tsx index e91edb8db4dc8..2e0c07a173ce1 100644 --- a/packages/frontend/core/src/components/mobile/config-modal/index.tsx +++ b/packages/frontend/core/src/components/mobile/config-modal/index.tsx @@ -1,4 +1,5 @@ import { Button, Modal } from '@affine/component'; +import { PageHeader } from '@affine/core/mobile/components'; import { useI18n } from '@affine/i18n'; import clsx from 'clsx'; import { @@ -8,7 +9,6 @@ import { type ReactNode, } from 'react'; -import { PageHeader } from '../page-header'; import * as styles from './styles.css'; interface ConfigModalProps { diff --git a/packages/frontend/core/src/components/mobile/index.ts b/packages/frontend/core/src/components/mobile/index.ts index d9dfbc4fa24e7..3bbf215aeae83 100644 --- a/packages/frontend/core/src/components/mobile/index.ts +++ b/packages/frontend/core/src/components/mobile/index.ts @@ -1,2 +1 @@ export * from './config-modal'; -export * from './page-header'; diff --git a/packages/frontend/core/src/mobile/components/index.ts b/packages/frontend/core/src/mobile/components/index.ts index 2cbbc0f58069d..18dd7f3f65612 100644 --- a/packages/frontend/core/src/mobile/components/index.ts +++ b/packages/frontend/core/src/mobile/components/index.ts @@ -1,5 +1,6 @@ export * from './app-tabs'; export * from './doc-card'; +export * from './page-header'; export * from './rename'; export * from './search-input'; export * from './search-result'; diff --git a/packages/frontend/core/src/components/mobile/page-header/index.tsx b/packages/frontend/core/src/mobile/components/page-header/index.tsx similarity index 76% rename from packages/frontend/core/src/components/mobile/page-header/index.tsx rename to packages/frontend/core/src/mobile/components/page-header/index.tsx index bcc22e03de01e..536d67d880605 100644 --- a/packages/frontend/core/src/components/mobile/page-header/index.tsx +++ b/packages/frontend/core/src/mobile/components/page-header/index.tsx @@ -1,13 +1,16 @@ -import { IconButton, SafeArea } from '@affine/component'; -import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc'; +import { IconButton, SafeArea, useIsInsideModal } from '@affine/component'; +import { ArrowLeftSmallIcon, CloseIcon } from '@blocksuite/icons/rc'; +import { useService } from '@toeverything/infra'; import clsx from 'clsx'; import { forwardRef, type HtmlHTMLAttributes, type ReactNode, useCallback, + useEffect, } from 'react'; +import { NavigationGestureService } from '../../modules/navigation-gesture'; import * as styles from './styles.css'; export interface PageHeaderProps @@ -60,6 +63,20 @@ export const PageHeader = forwardRef( }, ref ) { + const navigationGesture = useService(NavigationGestureService); + const isInsideModal = useIsInsideModal(); + + useEffect(() => { + if (isInsideModal) return; + + const prev = navigationGesture.enabled$.value; + navigationGesture.setEnabled(!!back); + + return () => { + navigationGesture.setEnabled(prev); + }; + }, [back, isInsideModal, navigationGesture]); + const handleRouteBack = useCallback(() => { backAction ? backAction() : history.back(); }, [backAction]); @@ -83,7 +100,7 @@ export const PageHeader = forwardRef( size={24} style={{ padding: 10 }} onClick={handleRouteBack} - icon={} + icon={isInsideModal ? : } data-testid="page-header-back" /> ) : null} diff --git a/packages/frontend/core/src/components/mobile/page-header/styles.css.ts b/packages/frontend/core/src/mobile/components/page-header/styles.css.ts similarity index 100% rename from packages/frontend/core/src/components/mobile/page-header/styles.css.ts rename to packages/frontend/core/src/mobile/components/page-header/styles.css.ts diff --git a/packages/frontend/core/src/mobile/dialogs/selectors/generic-selector.tsx b/packages/frontend/core/src/mobile/dialogs/selectors/generic-selector.tsx index 24eda1497d863..99815b8dab821 100644 --- a/packages/frontend/core/src/mobile/dialogs/selectors/generic-selector.tsx +++ b/packages/frontend/core/src/mobile/dialogs/selectors/generic-selector.tsx @@ -5,7 +5,7 @@ import { Scrollable, useThemeColorMeta, } from '@affine/component'; -import { PageHeader } from '@affine/core/components/mobile'; +import { PageHeader } from '@affine/core/mobile/components'; import { useI18n } from '@affine/i18n'; import { ArrowRightSmallIcon } from '@blocksuite/icons/rc'; import { cssVarV2 } from '@toeverything/theme/v2'; diff --git a/packages/frontend/core/src/mobile/modules/index.ts b/packages/frontend/core/src/mobile/modules/index.ts index 106fdfc1c4e73..c316ca05fbca6 100644 --- a/packages/frontend/core/src/mobile/modules/index.ts +++ b/packages/frontend/core/src/mobile/modules/index.ts @@ -1,9 +1,11 @@ import type { Framework } from '@toeverything/infra'; +import { configureMobileNavigationGestureModule } from './navigation-gesture'; import { configureMobileSearchModule } from './search'; import { configureMobileVirtualKeyboardModule } from './virtual-keyboard'; export function configureMobileModules(framework: Framework) { configureMobileSearchModule(framework); configureMobileVirtualKeyboardModule(framework); + configureMobileNavigationGestureModule(framework); } diff --git a/packages/frontend/core/src/mobile/modules/navigation-gesture/index.ts b/packages/frontend/core/src/mobile/modules/navigation-gesture/index.ts new file mode 100644 index 0000000000000..efe25a8e3e0f4 --- /dev/null +++ b/packages/frontend/core/src/mobile/modules/navigation-gesture/index.ts @@ -0,0 +1,13 @@ +import type { Framework } from '@toeverything/infra'; + +import { NavigationGestureProvider } from './providers/navigation-gesture'; +import { NavigationGestureService } from './services/navigation-gesture'; + +export { NavigationGestureProvider, NavigationGestureService }; + +export function configureMobileNavigationGestureModule(framework: Framework) { + framework.service( + NavigationGestureService, + f => new NavigationGestureService(f.getOptional(NavigationGestureProvider)) + ); +} diff --git a/packages/frontend/core/src/mobile/modules/navigation-gesture/providers/navigation-gesture.ts b/packages/frontend/core/src/mobile/modules/navigation-gesture/providers/navigation-gesture.ts new file mode 100644 index 0000000000000..4906c19877e29 --- /dev/null +++ b/packages/frontend/core/src/mobile/modules/navigation-gesture/providers/navigation-gesture.ts @@ -0,0 +1,10 @@ +import { createIdentifier } from '@toeverything/infra'; + +export interface NavigationGestureProvider { + isEnabled: () => Promise; + enable: () => Promise; + disable: () => Promise; +} + +export const NavigationGestureProvider = + createIdentifier('NavigationGestureProvider'); diff --git a/packages/frontend/core/src/mobile/modules/navigation-gesture/services/navigation-gesture.ts b/packages/frontend/core/src/mobile/modules/navigation-gesture/services/navigation-gesture.ts new file mode 100644 index 0000000000000..6222de9616741 --- /dev/null +++ b/packages/frontend/core/src/mobile/modules/navigation-gesture/services/navigation-gesture.ts @@ -0,0 +1,58 @@ +import { DebugLogger } from '@affine/debug'; +import { + effect, + exhaustMapWithTrailing, + fromPromise, + LiveData, + Service, +} from '@toeverything/infra'; +import { catchError, distinctUntilChanged, EMPTY, mergeMap } from 'rxjs'; + +import type { NavigationGestureProvider } from '../providers/navigation-gesture'; + +const logger = new DebugLogger('affine:navigation-gesture'); + +export class NavigationGestureService extends Service { + public enabled$ = new LiveData(false); + + constructor( + private readonly navigationGestureProvider?: NavigationGestureProvider + ) { + super(); + } + + setEnabled = effect( + distinctUntilChanged(), + exhaustMapWithTrailing((enable: boolean) => { + return fromPromise(async () => { + if (!this.navigationGestureProvider) { + return; + } + if (enable) { + await this.enable(); + } else { + await this.disable(); + } + return; + }).pipe( + mergeMap(() => EMPTY), + catchError(err => { + logger.error('navigationGestureProvider error', err); + return EMPTY; + }) + ); + }) + ); + + async enable() { + this.enabled$.next(true); + logger.debug(`Enable navigation gesture`); + return this.navigationGestureProvider?.enable(); + } + + async disable() { + this.enabled$.next(false); + logger.debug(`Disable navigation gesture`); + return this.navigationGestureProvider?.disable(); + } +} diff --git a/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx b/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx index a315218eabc98..3c69993c60578 100644 --- a/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx +++ b/packages/frontend/core/src/mobile/pages/workspace/detail/mobile-detail-page.tsx @@ -7,9 +7,9 @@ import { useDocMetaHelper } from '@affine/core/components/hooks/use-block-suite- import { usePageDocumentTitle } from '@affine/core/components/hooks/use-global-state'; import { useJournalRouteHelper } from '@affine/core/components/hooks/use-journal'; import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper'; -import { PageHeader } from '@affine/core/components/mobile'; import { PageDetailEditor } from '@affine/core/components/page-detail-editor'; import { DetailPageWrapper } from '@affine/core/desktop/pages/workspace/detail-page/detail-page-wrapper'; +import { PageHeader } from '@affine/core/mobile/components'; import { EditorService } from '@affine/core/modules/editor'; import { JournalService } from '@affine/core/modules/journal'; import { WorkbenchService } from '@affine/core/modules/workbench'; @@ -202,19 +202,22 @@ const DetailPageImpl = () => { ); }; -const skeleton = ( +const getSkeleton = (back: boolean) => ( <> - + ); - -const notFound = ( +const getNotFound = (back: boolean) => ( <> - + Page Not Found (TODO) ); +const skeleton = getSkeleton(false); +const skeletonWithBack = getSkeleton(true); +const notFound = getNotFound(false); +const notFoundWithBack = getNotFound(true); const MobileDetailPage = ({ pageId, @@ -237,12 +240,12 @@ const MobileDetailPage = ({ return (
diff --git a/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx b/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx index 95c157f8201d7..e1a688f567d17 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/collection/detail.tsx @@ -1,7 +1,7 @@ import { IconButton, MobileMenu } from '@affine/component'; import { EmptyCollectionDetail } from '@affine/core/components/affine/empty'; -import { PageHeader } from '@affine/core/components/mobile'; import { isEmptyCollection } from '@affine/core/desktop/pages/workspace/collection'; +import { PageHeader } from '@affine/core/mobile/components'; import type { Collection } from '@affine/env/filter'; import { MoreHorizontalIcon, ViewLayersIcon } from '@blocksuite/icons/rc'; diff --git a/packages/frontend/core/src/mobile/views/all-docs/tag/detail-header.tsx b/packages/frontend/core/src/mobile/views/all-docs/tag/detail-header.tsx index be56ae9208252..c588258089030 100644 --- a/packages/frontend/core/src/mobile/views/all-docs/tag/detail-header.tsx +++ b/packages/frontend/core/src/mobile/views/all-docs/tag/detail-header.tsx @@ -1,5 +1,5 @@ import { IconButton, MobileMenu } from '@affine/component'; -import { PageHeader } from '@affine/core/components/mobile'; +import { PageHeader } from '@affine/core/mobile/components'; import type { Tag } from '@affine/core/modules/tag'; import { MoreHorizontalIcon } from '@blocksuite/icons/rc'; import { useLiveData } from '@toeverything/infra';