From e0d1af70a2000027be82ebd59628bfafc6b1b267 Mon Sep 17 00:00:00 2001 From: cucadmuh <49571317+cucadmuh@users.noreply.github.com> Date: Sat, 20 Jun 2026 00:33:24 +0300 Subject: [PATCH] feat(ui): enable touchpad back/forward navigation gestures Wire native WebKit/WebView2 swipe-to-navigate settings (issue #935) with a Settings toggle defaulting on, applied to main and mini webviews. --- src-tauri/Cargo.lock | 25 ++++++ src-tauri/Cargo.toml | 2 + src-tauri/src/lib.rs | 1 + src-tauri/src/lib_commands/app_api/mod.rs | 3 +- .../src/lib_commands/app_api/platform.rs | 79 +++++++++++++++++++ src/components/MiniPlayer.test.tsx | 1 + src/components/settings/SystemTab.tsx | 7 ++ src/components/settings/settingsTabs.ts | 2 +- src/hooks/useMiniWindowSetup.ts | 16 ++-- src/hooks/usePlatformShellSetup.ts | 19 +++++ src/locales/de/settings.ts | 3 + src/locales/en/settings.ts | 6 ++ src/locales/es/settings.ts | 3 + src/locales/fr/settings.ts | 3 + src/locales/nb/settings.ts | 3 + src/locales/nl/settings.ts | 3 + src/locales/ro/settings.ts | 3 + src/locales/ru/settings.ts | 6 ++ src/locales/zh/settings.ts | 2 + src/store/authStore.settings.test.ts | 1 + src/store/authStore.ts | 1 + src/store/authStoreTypes.ts | 3 + src/store/authUiAppearanceActions.ts | 2 + 23 files changed, 186 insertions(+), 8 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 89c0b5b6..792b45cb 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3496,6 +3496,16 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-javascript-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" +dependencies = [ + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc2-osa-kit" version = "0.3.2" @@ -3520,6 +3530,17 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.11.1", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -3563,6 +3584,8 @@ dependencies = [ "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", + "objc2-javascript-core", + "objc2-security", ] [[package]] @@ -4127,6 +4150,7 @@ dependencies = [ "lofty", "mach2", "md5", + "objc2-web-kit", "psysonic-analysis", "psysonic-audio", "psysonic-core", @@ -4160,6 +4184,7 @@ dependencies = [ "webkit2gtk", "webkit2gtk-nvidia-quirk", "webp", + "webview2-com", "windows 0.62.2", "zbus 5.16.0", "zip 8.6.0", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 2730e648..35bcb714 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -83,6 +83,7 @@ libc = "0.2" [target.'cfg(target_os = "macos")'.dependencies] mach2 = "0.5" +objc2-web-kit = "0.3" [target.'cfg(target_os = "linux")'.dependencies] zbus = { version = "5.16", default-features = false, features = ["blocking-api", "async-io"] } @@ -91,6 +92,7 @@ webkit2gtk = { version = "2.0", default-features = false, features = ["v2_40"] } webkit2gtk-nvidia-quirk = "1.3" [target.'cfg(windows)'.dependencies] +webview2-com = "0.38" windows = { version = "0.62", features = [ "Win32_Foundation", "Win32_Graphics", diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f9f3ea73..3b89986f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -689,6 +689,7 @@ pub fn run() { cli_publish_server_list, cli_publish_search_results, set_window_decorations, + set_back_forward_navigation_gestures, set_linux_webkit_smooth_scrolling, linux_wayland_gpu_font_tuning_active, linux_wayland_text_render_settings_available, diff --git a/src-tauri/src/lib_commands/app_api/mod.rs b/src-tauri/src/lib_commands/app_api/mod.rs index 8193ef07..20f1bb7f 100644 --- a/src-tauri/src/lib_commands/app_api/mod.rs +++ b/src-tauri/src/lib_commands/app_api/mod.rs @@ -22,7 +22,8 @@ pub(crate) use core::{ pub(crate) use perf::performance_cpu_snapshot; pub(crate) use platform::{ linux_wayland_gpu_font_tuning_active, linux_wayland_text_render_settings_available, - set_linux_wayland_text_render_profile, set_linux_webkit_smooth_scrolling, set_window_decorations, + set_back_forward_navigation_gestures, set_linux_wayland_text_render_profile, + set_linux_webkit_smooth_scrolling, set_window_decorations, theme_animation_risk, }; #[cfg(target_os = "linux")] diff --git a/src-tauri/src/lib_commands/app_api/platform.rs b/src-tauri/src/lib_commands/app_api/platform.rs index 712259a3..6a833202 100644 --- a/src-tauri/src/lib_commands/app_api/platform.rs +++ b/src-tauri/src/lib_commands/app_api/platform.rs @@ -208,6 +208,85 @@ pub(crate) fn linux_webkit_apply_smooth_scrolling(win: &tauri::WebviewWindow, en .map_err(|e| e.to_string()) } +/// WebKitGTK / WKWebView / WebView2: two-finger horizontal swipe for history back/forward. +#[cfg(target_os = "linux")] +pub(crate) fn webview_apply_back_forward_navigation_gestures( + win: &tauri::WebviewWindow, + enabled: bool, +) -> Result<(), String> { + win.with_webview(move |platform| { + use webkit2gtk::{SettingsExt, WebViewExt}; + if let Some(settings) = platform.inner().settings() { + settings.set_enable_back_forward_navigation_gestures(enabled); + } + }) + .map_err(|e| e.to_string()) +} + +#[cfg(target_os = "macos")] +pub(crate) fn webview_apply_back_forward_navigation_gestures( + win: &tauri::WebviewWindow, + enabled: bool, +) -> Result<(), String> { + win.with_webview(move |platform| { + use objc2_web_kit::WKWebView; + let ptr = platform.inner(); + if ptr.is_null() { + return; + } + unsafe { + let webview = &*(ptr as *const WKWebView); + webview.setAllowsBackForwardNavigationGestures(enabled); + } + }) + .map_err(|e| e.to_string()) +} + +#[cfg(windows)] +pub(crate) fn webview_apply_back_forward_navigation_gestures( + win: &tauri::WebviewWindow, + enabled: bool, +) -> Result<(), String> { + use webview2_com::Microsoft::Web::WebView2::Win32::*; + use windows::core::Interface; + win.with_webview(move |platform| { + let controller = platform.controller(); + unsafe { + if let Ok(webview) = controller.CoreWebView2() { + if let Ok(settings) = webview.Settings() { + if let Ok(settings6) = settings.cast::() { + let _ = settings6.SetIsSwipeNavigationEnabled(enabled); + } + } + } + } + }) + .map_err(|e| e.to_string()) +} + +#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))] +pub(crate) fn webview_apply_back_forward_navigation_gestures( + _win: &tauri::WebviewWindow, + _enabled: bool, +) -> Result<(), String> { + Ok(()) +} + +/// Called from the frontend settings toggle; applies to every open webview window. +#[tauri::command] +pub(crate) fn set_back_forward_navigation_gestures( + enabled: bool, + app_handle: tauri::AppHandle, +) -> Result<(), String> { + use tauri::Manager; + for label in ["main", "mini"] { + if let Some(win) = app_handle.get_webview_window(label) { + webview_apply_back_forward_navigation_gestures(&win, enabled)?; + } + } + Ok(()) +} + /// Called from the frontend settings toggle (Linux); no-op on other platforms. #[tauri::command] pub(crate) fn set_linux_webkit_smooth_scrolling(enabled: bool, app_handle: tauri::AppHandle) -> Result<(), String> { diff --git a/src/components/MiniPlayer.test.tsx b/src/components/MiniPlayer.test.tsx index 42649672..9fdf9534 100644 --- a/src/components/MiniPlayer.test.tsx +++ b/src/components/MiniPlayer.test.tsx @@ -46,6 +46,7 @@ beforeEach(() => { onInvoke('audio_get_state', () => ({ playing: false })); onInvoke('set_window_always_on_top', () => undefined); onInvoke('set_linux_webkit_smooth_scrolling', () => undefined); + onInvoke('set_back_forward_navigation_gestures', () => undefined); onInvoke('discord_update_presence', () => undefined); }); diff --git a/src/components/settings/SystemTab.tsx b/src/components/settings/SystemTab.tsx index fa5afc22..6bc3b16d 100644 --- a/src/components/settings/SystemTab.tsx +++ b/src/components/settings/SystemTab.tsx @@ -99,6 +99,13 @@ export function SystemTab() { checked={auth.minimizeToTray} onChange={auth.setMinimizeToTray} /> +
+ {IS_LINUX && ( diff --git a/src/components/settings/settingsTabs.ts b/src/components/settings/settingsTabs.ts index 5284b68c..661b376f 100644 --- a/src/components/settings/settingsTabs.ts +++ b/src/components/settings/settingsTabs.ts @@ -71,7 +71,7 @@ export const SETTINGS_INDEX: SearchIndexEntry[] = [ { tab: 'input', titleKey: 'settings.inputKeybindingsTitle', keywords: 'keybindings shortcuts hotkeys keyboard' }, { tab: 'input', titleKey: 'settings.globalShortcutsTitle', keywords: 'global shortcuts hotkeys system-wide media keys' }, { tab: 'system', titleKey: 'settings.language', keywords: 'language locale translation i18n' }, - { tab: 'system', titleKey: 'settings.behavior', keywords: 'behavior tray minimize close start smooth scroll linux' }, + { tab: 'system', titleKey: 'settings.behavior', keywords: 'behavior tray minimize close start smooth scroll linux swipe back forward touchpad gesture navigation' }, { tab: 'system', titleKey: 'settings.backupTitle', keywords: 'backup export import settings restore' }, { tab: 'system', titleKey: 'settings.loggingTitle', keywords: 'log logs diagnostic debug verbose' }, { tab: 'system', titleKey: 'settings.aboutTitle', keywords: 'about version update changelog release notes' }, diff --git a/src/hooks/useMiniWindowSetup.ts b/src/hooks/useMiniWindowSetup.ts index 62988478..26658b66 100644 --- a/src/hooks/useMiniWindowSetup.ts +++ b/src/hooks/useMiniWindowSetup.ts @@ -16,15 +16,19 @@ import { * actually brings the window to the foreground. */ export function useMiniWindowSetup(alwaysOnTop: boolean, initialQueueOpen: boolean) { useEffect(() => { - if (!IS_LINUX) return; - const apply = () => { - invoke('set_linux_webkit_smooth_scrolling', { - enabled: useAuthStore.getState().linuxWebkitKineticScroll, + const applyWebviewPrefs = () => { + invoke('set_back_forward_navigation_gestures', { + enabled: useAuthStore.getState().touchpadBackForwardGestures, }).catch(() => {}); + if (IS_LINUX) { + invoke('set_linux_webkit_smooth_scrolling', { + enabled: useAuthStore.getState().linuxWebkitKineticScroll, + }).catch(() => {}); + } }; - apply(); + applyWebviewPrefs(); return useAuthStore.persist.onFinishHydration(() => { - apply(); + applyWebviewPrefs(); }); }, []); diff --git a/src/hooks/usePlatformShellSetup.ts b/src/hooks/usePlatformShellSetup.ts index 417e4577..78b9c25a 100644 --- a/src/hooks/usePlatformShellSetup.ts +++ b/src/hooks/usePlatformShellSetup.ts @@ -15,6 +15,7 @@ export function usePlatformShellSetup(): { isTilingWm: boolean } { const [isTilingWm, setIsTilingWm] = useState(false); const [waylandTextUi, setWaylandTextUi] = useState(false); const useCustomTitlebar = useAuthStore(s => s.useCustomTitlebar); + const touchpadBackForwardGestures = useAuthStore(s => s.touchpadBackForwardGestures); const linuxWebkitKineticScroll = useAuthStore(s => s.linuxWebkitKineticScroll); const linuxWaylandTextRenderProfile = useAuthStore(s => s.linuxWaylandTextRenderProfile); const loggingMode = useAuthStore(s => s.loggingMode); @@ -87,6 +88,24 @@ export function usePlatformShellSetup(): { isTilingWm: boolean } { invoke('set_window_decorations', { enabled }).catch(() => {}); }, [useCustomTitlebar, isTilingWm]); + useEffect(() => { + invoke('set_back_forward_navigation_gestures', { enabled: touchpadBackForwardGestures }).catch(() => {}); + }, [touchpadBackForwardGestures]); + + useEffect(() => { + const applyFromStore = () => { + invoke('set_back_forward_navigation_gestures', { + enabled: useAuthStore.getState().touchpadBackForwardGestures, + }).catch(() => {}); + }; + if (useAuthStore.persist.hasHydrated()) { + applyFromStore(); + } + return useAuthStore.persist.onFinishHydration(() => { + applyFromStore(); + }); + }, []); + useEffect(() => { if (!IS_LINUX) return; invoke('set_linux_webkit_smooth_scrolling', { enabled: linuxWebkitKineticScroll }).catch(() => {}); diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts index e21261fd..64193a8b 100644 --- a/src/locales/de/settings.ts +++ b/src/locales/de/settings.ts @@ -220,6 +220,9 @@ export const settings = { showTrayIconDesc: 'Psysonic-Icon im System-Tray / in der Menüleiste anzeigen.', minimizeToTray: 'Im Tray minimieren', minimizeToTrayDesc: 'Beim Schließen des Fensters läuft Psysonic weiter im System-Tray statt zu beenden.', + touchpadBackForwardGestures: 'Wischen für Zurück / Vor', + touchpadBackForwardGesturesDesc: + 'Zwei-Finger-Wischgeste auf dem Touchpad blättert in der App-Navigation wie im Browser.', clockFormat: 'Uhrzeitformat', clockFormatDesc: 'Format für die Queue-ETA und die Vorschau des Sleep-Timers.', clockFormatAuto: 'Automatisch (Systemsprache)', diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts index 3db3f6de..ad48ff9f 100644 --- a/src/locales/en/settings.ts +++ b/src/locales/en/settings.ts @@ -223,6 +223,12 @@ export const settings = { showTrayIconDesc: 'Display the Psysonic icon in the system notification area / menu bar.', minimizeToTray: 'Minimize to Tray', minimizeToTrayDesc: 'When closing the window, keep Psysonic running in the system tray instead of quitting.', + touchpadBackForwardGestures: 'Swipe to go back / forward', + touchpadBackForwardGesturesDesc: + 'Two-finger horizontal touchpad swipe navigates in-app history, like in a browser.', + touchpadBackForwardGestures: 'Swipe to go back / forward', + touchpadBackForwardGesturesDesc: + 'Two-finger horizontal touchpad swipe navigates in-app history, like in a browser.', clockFormat: 'Clock Format', clockFormatDesc: 'Wall-clock display used by the queue ETA and the sleep-timer preview.', clockFormatAuto: 'Auto (system locale)', diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts index 842c33d7..552c22df 100644 --- a/src/locales/es/settings.ts +++ b/src/locales/es/settings.ts @@ -219,6 +219,9 @@ export const settings = { showTrayIconDesc: 'Muestra el icono de Psysonic en el área de notificación / barra de menú.', minimizeToTray: 'Minimizar a Bandeja', minimizeToTrayDesc: 'Al cerrar la ventana, mantener Psysonic ejecutándose en la bandeja del sistema en lugar de salir.', + touchpadBackForwardGestures: 'Deslizar para atrás / adelante', + touchpadBackForwardGesturesDesc: + 'Deslizar horizontalmente con dos dedos en el touchpad navega el historial de la app, como en un navegador.', clockFormat: 'Formato de hora', clockFormatDesc: 'Formato del reloj utilizado por la ETA de la cola y la vista previa del temporizador de suspensión.', clockFormatAuto: 'Automático (idioma del sistema)', diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts index 3732b68e..7f7d05a6 100644 --- a/src/locales/fr/settings.ts +++ b/src/locales/fr/settings.ts @@ -219,6 +219,9 @@ export const settings = { showTrayIconDesc: 'Affiche l\'icône Psysonic dans la zone de notification / barre des menus.', minimizeToTray: 'Réduire dans la barre système', minimizeToTrayDesc: 'Lors de la fermeture, Psysonic continue de fonctionner dans la barre système au lieu de se fermer.', + touchpadBackForwardGestures: 'Balayer pour précédent / suivant', + touchpadBackForwardGesturesDesc: + 'Un balayage horizontal à deux doigts sur le pavé tactile parcourt l’historique de navigation, comme dans un navigateur.', clockFormat: 'Format de l\'heure', clockFormatDesc: 'Format de l\'horloge utilisé par l\'ETA de la file d\'attente et l\'aperçu du minuteur de mise en veille.', clockFormatAuto: 'Automatique (langue du système)', diff --git a/src/locales/nb/settings.ts b/src/locales/nb/settings.ts index ee9393fe..ced4ca4a 100644 --- a/src/locales/nb/settings.ts +++ b/src/locales/nb/settings.ts @@ -218,6 +218,9 @@ export const settings = { showOrbitTriggerDesc: 'Knappen i toppen for å starte eller bli med i en delt lytteøkt. Skjul den hvis du ikke bruker Orbit — du kan slå den på igjen her.', minimizeToTray: 'Minimer til oppgavelinjen', minimizeToTrayDesc: 'Når vinduet lukkes, vil Psysonic bli kjørende i oppgavelinjen fremfor å bli avsluttet.', + touchpadBackForwardGestures: 'Sveip tilbake / frem', + touchpadBackForwardGesturesDesc: + 'Horisontalt sveip med to fingre på styreplaten navigerer i appens historikk, som i en nettleser.', clockFormat: 'Klokkeformat', clockFormatDesc: 'Klokkevisning brukt av kø-ETA og forhåndsvisningen av hviletimeren.', clockFormatAuto: 'Automatisk (systemspråk)', diff --git a/src/locales/nl/settings.ts b/src/locales/nl/settings.ts index 3adc8eed..7dc4b955 100644 --- a/src/locales/nl/settings.ts +++ b/src/locales/nl/settings.ts @@ -219,6 +219,9 @@ export const settings = { showTrayIconDesc: 'Toont het Psysonic-pictogram in het systeemvak / de menubalk.', minimizeToTray: 'Minimaliseren naar systeemvak', minimizeToTrayDesc: 'Bij het sluiten van het venster blijft Psysonic actief in het systeemvak in plaats van af te sluiten.', + touchpadBackForwardGestures: 'Veeg terug / vooruit', + touchpadBackForwardGesturesDesc: + 'Horizontaal vegen met twee vingers op het touchpad doorloopt de navigatiegeschiedenis, zoals in een browser.', clockFormat: 'Tijdformaat', clockFormatDesc: 'Tijdsweergave voor de wachtrij-ETA en het voorbeeld van de slaaptimer.', clockFormatAuto: 'Automatisch (systeemtaal)', diff --git a/src/locales/ro/settings.ts b/src/locales/ro/settings.ts index 12e01a0c..7809a0ef 100644 --- a/src/locales/ro/settings.ts +++ b/src/locales/ro/settings.ts @@ -222,6 +222,9 @@ export const settings = { showTrayIconDesc: 'Afișează iconița Psysonic în zona notificărilor de sistem / bara de meniu.', minimizeToTray: 'Minimizează în Tavă', minimizeToTrayDesc: 'La închiderea ferestrei, continuă rularea Psysonic în tava de sistem în loc de ieșire', + touchpadBackForwardGestures: 'Glisare înapoi / înainte', + touchpadBackForwardGesturesDesc: + 'Glisarea orizontală cu două degete pe touchpad parcurge istoricul de navigare din aplicație, ca într-un browser.', clockFormat: 'Format Oră', clockFormatDesc: 'Format al ceasului folosit pentru ETA-ul cozii și previzualizarea cronometrului de somn.', clockFormatAuto: 'Automat (limba sistemului)', diff --git a/src/locales/ru/settings.ts b/src/locales/ru/settings.ts index 9bf821db..cc2e72f5 100644 --- a/src/locales/ru/settings.ts +++ b/src/locales/ru/settings.ts @@ -224,6 +224,12 @@ export const settings = { showTrayIconDesc: 'Показывать Psysonic в области уведомлений / строке меню.', minimizeToTray: 'Сворачивать в трей', minimizeToTrayDesc: 'При закрытии окна не выходить из приложения, а оставаться в трее.', + touchpadBackForwardGestures: 'Свайп назад / вперёд', + touchpadBackForwardGesturesDesc: + 'Горизонтальный свайп двумя пальцами по тачпаду перелистывает историю навигации в приложении, как в браузере.', + touchpadBackForwardGestures: 'Свайп назад / вперёд', + touchpadBackForwardGesturesDesc: + 'Горизонтальный свайп двумя пальцами по тачпаду перелистывает историю навигации в приложении, как в браузере.', clockFormat: 'Формат времени', clockFormatDesc: 'Формат времени для ETA очереди и предпросмотра таймера сна.', clockFormatAuto: 'Авто (системный)', diff --git a/src/locales/zh/settings.ts b/src/locales/zh/settings.ts index 1c90d816..b3a3d9c1 100644 --- a/src/locales/zh/settings.ts +++ b/src/locales/zh/settings.ts @@ -219,6 +219,8 @@ export const settings = { showTrayIconDesc: '在系统通知区域 / 菜单栏显示 Psysonic 图标。', minimizeToTray: '最小化到托盘', minimizeToTrayDesc: '关闭窗口时,Psysonic 将继续在系统托盘中运行,而不是退出。', + touchpadBackForwardGestures: '触控板左右滑动前进/后退', + touchpadBackForwardGesturesDesc: '在触控板上双指水平滑动,可像浏览器一样在应用内历史中前进或后退。', clockFormat: '时间格式', clockFormatDesc: '队列预计结束时间和睡眠定时器预览使用的时间格式。', clockFormatAuto: '自动(跟随系统)', diff --git a/src/store/authStore.settings.test.ts b/src/store/authStore.settings.test.ts index 6de3ecbb..1cddeb82 100644 --- a/src/store/authStore.settings.test.ts +++ b/src/store/authStore.settings.test.ts @@ -61,6 +61,7 @@ describe('trivial pass-through setters', () => { ['setWindowButtonStyle', 'windowButtonStyle', 'flat'], ['setShowMinimizeButton', 'showMinimizeButton', false], ['setPreloadMiniPlayer', 'preloadMiniPlayer', true], + ['setTouchpadBackForwardGestures', 'touchpadBackForwardGestures', false], ['setLinuxWebkitKineticScroll', 'linuxWebkitKineticScroll', false], ['setLinuxWaylandTextRenderProfile', 'linuxWaylandTextRenderProfile', 'gpu'], ['setNowPlayingEnabled', 'nowPlayingEnabled', true], diff --git a/src/store/authStore.ts b/src/store/authStore.ts index daf80805..fadc1fc5 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -79,6 +79,7 @@ export const useAuthStore = create()( windowButtonStyle: 'dots', showMinimizeButton: true, preloadMiniPlayer: false, + touchpadBackForwardGestures: true, linuxWebkitKineticScroll: true, linuxWaylandTextRenderProfile: 'sharp', linuxWebkitInputForceRepaint: false, diff --git a/src/store/authStoreTypes.ts b/src/store/authStoreTypes.ts index 54245c5c..b29d264c 100644 --- a/src/store/authStoreTypes.ts +++ b/src/store/authStoreTypes.ts @@ -172,6 +172,8 @@ export interface AuthState { /** Pre-build the mini-player webview at app start on Linux/macOS so content is available instantly * on first open. Ignored on Windows — that platform always pre-creates as a hang workaround. */ preloadMiniPlayer: boolean; + /** Two-finger horizontal touchpad swipe for in-app history back/forward (WebKit / WebView2). */ + touchpadBackForwardGestures: boolean; /** Linux WebKitGTK: smooth wheel on when true; off only after explicit opt-out in Settings. */ linuxWebkitKineticScroll: boolean; /** Linux Wayland + GPU compositing: WebKit text rasterisation profile (live, no restart). */ @@ -375,6 +377,7 @@ export interface AuthState { setWindowButtonStyle: (v: WindowButtonStyle) => void; setShowMinimizeButton: (v: boolean) => void; setPreloadMiniPlayer: (v: boolean) => void; + setTouchpadBackForwardGestures: (v: boolean) => void; setLinuxWebkitKineticScroll: (v: boolean) => void; setLinuxWaylandTextRenderProfile: (v: LinuxWaylandTextRenderProfile) => void; setLinuxWebkitInputForceRepaint: (v: boolean) => void; diff --git a/src/store/authUiAppearanceActions.ts b/src/store/authUiAppearanceActions.ts index f7a6f36f..464d8324 100644 --- a/src/store/authUiAppearanceActions.ts +++ b/src/store/authUiAppearanceActions.ts @@ -22,6 +22,7 @@ export function createUiAppearanceActions(set: SetState): Pick< | 'setWindowButtonStyle' | 'setShowMinimizeButton' | 'setPreloadMiniPlayer' + | 'setTouchpadBackForwardGestures' | 'setLinuxWebkitKineticScroll' | 'setLinuxWaylandTextRenderProfile' | 'setLinuxWebkitInputForceRepaint' @@ -46,6 +47,7 @@ export function createUiAppearanceActions(set: SetState): Pick< setWindowButtonStyle: (v) => set({ windowButtonStyle: v }), setShowMinimizeButton: (v) => set({ showMinimizeButton: v }), setPreloadMiniPlayer: (v) => set({ preloadMiniPlayer: v }), + setTouchpadBackForwardGestures: (v) => set({ touchpadBackForwardGestures: v }), setLinuxWebkitKineticScroll: (v) => set({ linuxWebkitKineticScroll: v }), setLinuxWaylandTextRenderProfile: (v) => set({ linuxWaylandTextRenderProfile: v }), setLinuxWebkitInputForceRepaint: (v) => set({ linuxWebkitInputForceRepaint: v }),