mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(mobile): disable swipe back gesture when there is no back in header (#8876)
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
This commit is contained in:
@@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
E93B276B2CED92B1001409B8 /* NavigationGesturePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationGesturePlugin.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -65,7 +67,6 @@
|
||||
504EC3051FED79650016851F /* Products */,
|
||||
7F8756D8B27F46E3366F6CEA /* Pods */,
|
||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
|
||||
9D6A85312CCF6D6B00DAB35F /* Recovered References */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
sourceTree = "<group>";
|
||||
@@ -101,6 +102,7 @@
|
||||
9D90BE1A2CCB9876006677DB /* plugins */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E93B276A2CED9298001409B8 /* NavigationGesture */,
|
||||
9D90BE192CCB9876006677DB /* Cookie */,
|
||||
);
|
||||
path = plugins;
|
||||
@@ -122,6 +124,14 @@
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E93B276A2CED9298001409B8 /* NavigationGesture */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E93B276B2CED92B1001409B8 /* NavigationGesturePlugin.swift */,
|
||||
);
|
||||
path = NavigationGesture;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* 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 */,
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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([:])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
<FrameworkRoot framework={frameworkProvider}>
|
||||
<I18nProvider>
|
||||
<AffineContext store={getCurrentStore()}>
|
||||
<RouterProvider
|
||||
fallbackElement={<AppFallback />}
|
||||
router={router}
|
||||
future={future}
|
||||
/>
|
||||
<ModalConfigProvider>
|
||||
<RouterProvider
|
||||
fallbackElement={<AppFallback />}
|
||||
router={router}
|
||||
future={future}
|
||||
/>
|
||||
</ModalConfigProvider>
|
||||
</AffineContext>
|
||||
</I18nProvider>
|
||||
</FrameworkRoot>
|
||||
|
||||
28
packages/frontend/apps/ios/src/modal-config.tsx
Normal file
28
packages/frontend/apps/ios/src/modal-config.tsx
Normal file
@@ -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 (
|
||||
<ModalConfigContext.Provider value={{ onOpenChange }}>
|
||||
{children}
|
||||
</ModalConfigContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface NavigationGesturePlugin {
|
||||
isEnabled: () => Promise<boolean>;
|
||||
enable: () => Promise<void>;
|
||||
disable: () => Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
|
||||
import type { NavigationGesturePlugin } from './definitions';
|
||||
|
||||
const NavigationGesture =
|
||||
registerPlugin<NavigationGesturePlugin>('NavigationGesture');
|
||||
|
||||
export * from './definitions';
|
||||
export { NavigationGesture };
|
||||
Reference in New Issue
Block a user