Add navigation gesture support in mainWindow and ElectronContext
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Implemented navigation gestures in mainWindow.js to handle swipe and app-command events for back and forward navigation. - Enhanced ElectronContext.jsx to manage navigation history through IPC events and added horizontal scroll detection for improved user experience. - Introduced a debounce mechanism for navigation actions to prevent rapid triggering.
This commit is contained in:
parent
f0571c9c5c
commit
36a3e81f47
@ -149,6 +149,33 @@ function attachKeyboardShortcuts(browserWindow) {
|
||||
// Keyboard shortcuts for the main window can be added here if needed
|
||||
}
|
||||
|
||||
function sendNavigationGesture(browserWindow, direction) {
|
||||
if (!browserWindow || browserWindow.isDestroyed()) return
|
||||
browserWindow.webContents.send('navigation-gesture', direction)
|
||||
}
|
||||
|
||||
function setupNavigationGestures(browserWindow) {
|
||||
if (!browserWindow) return
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
browserWindow.on('swipe', (_event, direction) => {
|
||||
if (direction === 'left') {
|
||||
sendNavigationGesture(browserWindow, 'back')
|
||||
} else if (direction === 'right') {
|
||||
sendNavigationGesture(browserWindow, 'forward')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
browserWindow.on('app-command', (_event, command) => {
|
||||
if (command === 'browser-backward') {
|
||||
sendNavigationGesture(browserWindow, 'back')
|
||||
} else if (command === 'browser-forward') {
|
||||
sendNavigationGesture(browserWindow, 'forward')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setupWindowEvents() {
|
||||
if (!win) return
|
||||
win.on('maximize', () => {
|
||||
@ -199,6 +226,7 @@ export function createWindow() {
|
||||
|
||||
setupWindowEvents()
|
||||
attachKeyboardShortcuts(win)
|
||||
setupNavigationGestures(win)
|
||||
}
|
||||
|
||||
export function getWindow() {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { createContext, useCallback, useEffect, useState } from 'react'
|
||||
import { createContext, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
@ -32,12 +32,43 @@ export function isElectron() {
|
||||
|
||||
const ElectronContext = createContext()
|
||||
|
||||
function isInHorizontalScrollContainer(element) {
|
||||
let node = element
|
||||
while (node && node !== document.body) {
|
||||
const { overflowX } = window.getComputedStyle(node)
|
||||
if (
|
||||
(overflowX === 'auto' || overflowX === 'scroll') &&
|
||||
node.scrollWidth > node.clientWidth
|
||||
) {
|
||||
return true
|
||||
}
|
||||
node = node.parentElement
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const ElectronProvider = ({ children }) => {
|
||||
const [platform, setPlatform] = useState('unknown')
|
||||
const [isMaximized, setIsMaximized] = useState(false)
|
||||
const [isFullScreen, setIsFullScreen] = useState(false)
|
||||
const [electronAvailable] = useState(isElectron())
|
||||
const navigate = useNavigate()
|
||||
const lastNavigationAtRef = useRef(0)
|
||||
|
||||
const navigateHistory = useCallback(
|
||||
(direction) => {
|
||||
const now = Date.now()
|
||||
if (now - lastNavigationAtRef.current < 300) return
|
||||
lastNavigationAtRef.current = now
|
||||
|
||||
if (direction === 'back') {
|
||||
navigate(-1)
|
||||
} else if (direction === 'forward') {
|
||||
navigate(1)
|
||||
}
|
||||
},
|
||||
[navigate]
|
||||
)
|
||||
|
||||
// Function to open external URL via Electron
|
||||
const openExternalUrl = (url) => {
|
||||
@ -92,11 +123,47 @@ const ElectronProvider = ({ children }) => {
|
||||
}
|
||||
ipcRenderer.on('navigate', navigateHandler)
|
||||
|
||||
const navigationGestureHandler = (_event, direction) => {
|
||||
navigateHistory(direction)
|
||||
}
|
||||
ipcRenderer.on('navigation-gesture', navigationGestureHandler)
|
||||
|
||||
return () => {
|
||||
ipcRenderer.removeListener('navigate', navigateHandler)
|
||||
ipcRenderer.removeListener('navigation-gesture', navigationGestureHandler)
|
||||
ipcRenderer.removeListener('window-state', windowStateHandler)
|
||||
}
|
||||
}, [navigate])
|
||||
}, [navigate, navigateHistory])
|
||||
|
||||
useEffect(() => {
|
||||
if (!electronAvailable || platform !== 'darwin') return
|
||||
|
||||
let accumulatedDeltaX = 0
|
||||
let resetTimer
|
||||
|
||||
const handleWheel = (event) => {
|
||||
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return
|
||||
if (Math.abs(event.deltaX) < Math.abs(event.deltaY)) return
|
||||
if (Math.abs(event.deltaX) < 2) return
|
||||
if (isInHorizontalScrollContainer(event.target)) return
|
||||
|
||||
accumulatedDeltaX += event.deltaX
|
||||
clearTimeout(resetTimer)
|
||||
resetTimer = setTimeout(() => {
|
||||
if (Math.abs(accumulatedDeltaX) > 60) {
|
||||
navigateHistory(accumulatedDeltaX > 0 ? 'forward' : 'back')
|
||||
}
|
||||
accumulatedDeltaX = 0
|
||||
}, 80)
|
||||
}
|
||||
|
||||
window.addEventListener('wheel', handleWheel, { passive: true })
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('wheel', handleWheel)
|
||||
clearTimeout(resetTimer)
|
||||
}
|
||||
}, [electronAvailable, navigateHistory, platform])
|
||||
|
||||
// Window control handler
|
||||
const handleWindowControl = (action) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user