feat(mobile): swipe to open menu for explorer (#8953)

close AF-1803

- bump theme
- extract `SwipeHelper` and add `speed`, `direction` detection support
- new mobile `SwipeMenu` component
- integrate `SwipeMenu` to open a menu in Explorer
- New `Haptics` module for mobile, implemented in `ios` and `mobile`(`navigator.vibrate()`)

![CleanShot 2024-11-28 at 12.25.14.gif](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/LakojjjzZNf6ogjOVwKE/cba36660-f38a-473b-b85c-33540a406835.gif)
This commit is contained in:
CatsJuice
2024-12-02 03:27:01 +00:00
parent b600f2b0a2
commit 11b453f4d8
23 changed files with 457 additions and 45 deletions
+1
View File
@@ -13,6 +13,7 @@ def capacitor_pods
pod 'CapacitorCordova', :path => '../../../../../node_modules/@capacitor/ios'
pod 'CapacitorApp', :path => '../../../../../node_modules/@capacitor/app'
pod 'CapacitorBrowser', :path => '../../../../../node_modules/@capacitor/browser'
pod 'CapacitorHaptics', :path => '../../../../../node_modules/@capacitor/haptics'
pod 'CapacitorKeyboard', :path => '../../../../../node_modules/@capacitor/keyboard'
end
+17 -11
View File
@@ -1,12 +1,14 @@
PODS:
- Capacitor (6.1.2):
- Capacitor (6.2.0):
- CapacitorCordova
- CapacitorApp (6.0.1):
- CapacitorApp (6.0.2):
- Capacitor
- CapacitorBrowser (6.0.3):
- CapacitorBrowser (6.0.4):
- Capacitor
- CapacitorCordova (6.1.2)
- CapacitorKeyboard (6.0.2):
- CapacitorCordova (6.2.0)
- CapacitorHaptics (6.0.2):
- Capacitor
- CapacitorKeyboard (6.0.3):
- Capacitor
- CryptoSwift (1.8.3)
@@ -15,6 +17,7 @@ DEPENDENCIES:
- "CapacitorApp (from `../../../../../node_modules/@capacitor/app`)"
- "CapacitorBrowser (from `../../../../../node_modules/@capacitor/browser`)"
- "CapacitorCordova (from `../../../../../node_modules/@capacitor/ios`)"
- "CapacitorHaptics (from `../../../../../node_modules/@capacitor/haptics`)"
- "CapacitorKeyboard (from `../../../../../node_modules/@capacitor/keyboard`)"
- CryptoSwift (~> 1.8.3)
@@ -31,17 +34,20 @@ EXTERNAL SOURCES:
:path: "../../../../../node_modules/@capacitor/browser"
CapacitorCordova:
:path: "../../../../../node_modules/@capacitor/ios"
CapacitorHaptics:
:path: "../../../../../node_modules/@capacitor/haptics"
CapacitorKeyboard:
:path: "../../../../../node_modules/@capacitor/keyboard"
SPEC CHECKSUMS:
Capacitor: 679f9673fdf30597493a6362a5d5bf233d46abc2
CapacitorApp: 0bc633b4eae40a1f32cd2834788fad3bc42da6a1
CapacitorBrowser: aab1ed943b01c0365c4810538a8b3477e2d9f72e
CapacitorCordova: f48c89f96c319101cd2f0ce8a2b7449b5fb8b3dd
CapacitorKeyboard: 2700f9b18687be021e28b5a09b59eb151a46d5e0
Capacitor: 1f3c7b9802d958cd8c4eb63895fff85dff2e1eea
CapacitorApp: 2a8c3a0b0814322e5e6e15fe595f02c3808f0f8b
CapacitorBrowser: ef0529d16cd8839281050c350e7bbee4f5c6d65f
CapacitorCordova: b33e7f4aa4ed105dd43283acdd940964374a87d9
CapacitorHaptics: b53409aaca1203f79c6d0eb3ed5de40556339518
CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483
PODFILE CHECKSUM: 1b0d3fe81862c0e9ce712ddd0c5a0accd0097698
PODFILE CHECKSUM: e0c0ccf027ea6d51e476f0baf9d44d97b9a90a4b
COCOAPODS: 1.16.2
+1
View File
@@ -20,6 +20,7 @@
"@capacitor/app": "^6.0.1",
"@capacitor/browser": "^6.0.3",
"@capacitor/core": "^6.1.2",
"@capacitor/haptics": "^6.0.2",
"@capacitor/ios": "^6.1.2",
"@capacitor/keyboard": "^6.0.2",
"@sentry/react": "^8.0.0",
+10
View File
@@ -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 { HapticProvider } from '@affine/core/mobile/modules/haptics';
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';
@@ -22,6 +23,7 @@ import {
} from '@affine/core/modules/workspace-engine';
import { App as CapacitorApp } from '@capacitor/app';
import { Browser } from '@capacitor/browser';
import { Haptics } from '@capacitor/haptics';
import { Keyboard } from '@capacitor/keyboard';
import {
Framework,
@@ -94,6 +96,14 @@ framework.impl(NavigationGestureProvider, {
enable: () => NavigationGesture.enable(),
disable: () => NavigationGesture.disable(),
});
framework.impl(HapticProvider, {
impact: options => Haptics.impact(options as any),
vibrate: options => Haptics.vibrate(options as any),
notification: options => Haptics.notification(options as any),
selectionStart: () => Haptics.selectionStart(),
selectionChanged: () => Haptics.selectionChanged(),
selectionEnd: () => Haptics.selectionEnd(),
});
const frameworkProvider = framework.provider();
// setup application lifecycle events, and emit application start event
+23
View File
@@ -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 { HapticProvider } from '@affine/core/mobile/modules/haptics';
import { router } from '@affine/core/mobile/router';
import { configureCommonModules } from '@affine/core/modules';
import { I18nProvider } from '@affine/core/modules/i18n';
@@ -52,6 +53,28 @@ framework.impl(PopupWindowProvider, {
window.open(url, '_blank', 'noreferrer noopener');
},
});
framework.impl(HapticProvider, {
impact: options => {
return new Promise(resolve => {
const style = options?.style ?? 'LIGHT';
const pattern = {
LIGHT: [10],
MEDIUM: [20],
HEAVY: [30],
}[style];
const result = navigator.vibrate?.(pattern);
if (!result) {
console.warn('vibrate not supported, or user not interacted');
}
resolve();
});
},
notification: () => Promise.reject('Not supported'),
vibrate: () => Promise.reject('Not supported'),
selectionStart: () => Promise.reject('Not supported'),
selectionChanged: () => Promise.reject('Not supported'),
selectionEnd: () => Promise.reject('Not supported'),
});
const frameworkProvider = framework.provider();
// setup application lifecycle events, and emit application start event