From b1b0be7b56d597282da40be2eef65c1def61ad9b Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 5 Feb 2026 22:35:43 +0700 Subject: [PATCH] Update files --- packages/app/src/utils/tauri-window.ts | 73 ++++++++++++------- packages/desktop/src-tauri/Info.plist | 16 ++++ .../src-tauri/capabilities/default.json | 6 ++ packages/desktop/src-tauri/src/main.rs | 6 ++ packages/desktop/src-tauri/tauri.conf.json | 5 +- 5 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 packages/desktop/src-tauri/Info.plist diff --git a/packages/app/src/utils/tauri-window.ts b/packages/app/src/utils/tauri-window.ts index 0257dddc2..95aadc764 100644 --- a/packages/app/src/utils/tauri-window.ts +++ b/packages/app/src/utils/tauri-window.ts @@ -14,21 +14,38 @@ async function getTauriWindow() { if (tauriWindow) return tauriWindow; // Double-check: both environment check AND platform check - if (!isTauriEnvironment() || !getIsTauriMac()) { + if (!isTauriEnvironment()) { return null; } try { - // Avoid emitting `import()` syntax into the Hermes bundle (it fails to parse), - // while still loading the Tauri module at runtime in the WebView. - const dynamicImport = new Function( - "moduleName", - "return import(moduleName)" - ) as (moduleName: string) => Promise; + // When `app.withGlobalTauri` is enabled, Tauri exposes its JS APIs on `window.__TAURI__`. + // We must use that here because importing `@tauri-apps/api/*` would be bundled into + // the native (Hermes) builds and break parsing/runtime on mobile. + const tauri = (window as any).__TAURI__ as any; - const { getCurrentWindow } = await dynamicImport("@tauri-apps/api/window"); - tauriWindow = getCurrentWindow(); - return tauriWindow; + // Prefer the public global window module. + const windowModule = tauri?.window; + if (windowModule && typeof windowModule.getCurrentWindow === "function") { + tauriWindow = windowModule.getCurrentWindow(); + return tauriWindow; + } + + // Fallback: core invoke (should exist when withGlobalTauri is enabled). + // We assume the main window label is "main" (default in Tauri when not specified). + const invoke = tauri?.core?.invoke; + if (typeof invoke === "function") { + tauriWindow = { + label: "main", + startDragging: () => invoke("plugin:window|start_dragging", { label: "main" }), + toggleMaximize: () => invoke("plugin:window|toggle_maximize", { label: "main" }), + isFullscreen: () => invoke("plugin:window|is_fullscreen", { label: "main" }), + onResized: (handler: (e: unknown) => void) => tauri?.event?.listen?.("tauri://resize", handler), + }; + return tauriWindow; + } + + return null; } catch { return null; } @@ -37,43 +54,49 @@ async function getTauriWindow() { export async function startDragging() { const win = await getTauriWindow(); if (win) { - await win.startDragging(); + try { + await win.startDragging(); + } catch (error) { + console.warn("[TauriWindow] startDragging failed", error); + } } } export async function toggleMaximize() { const win = await getTauriWindow(); if (win) { - await win.toggleMaximize(); + try { + await win.toggleMaximize(); + } catch (error) { + console.warn("[TauriWindow] toggleMaximize failed", error); + } } } // Returns event handlers for drag region behavior export function useTauriDragHandlers() { - if (Platform.OS !== "web" || !getIsTauriMac()) { + // Dragging should work on any desktop OS when running under Tauri. + if (Platform.OS !== "web" || !isTauriEnvironment()) { return {}; } return { onMouseDown: (e: React.MouseEvent) => { - // Only handle left click, ignore if clicking on interactive elements - if (e.button !== 0) return; + // Only handle primary button, ignore if clicking on interactive elements. + // Tauri docs recommend using `e.detail` on mousedown for double-click maximize. + if (typeof e.buttons === "number" ? e.buttons !== 1 : e.button !== 0) return; const target = e.target as HTMLElement; if (target.closest("button, a, input, [role='button']")) return; // Prevent text selection when dragging e.preventDefault(); - // Start dragging on mouse down - startDragging(); - }, - onDoubleClick: (e: React.MouseEvent) => { - // Ignore if clicking on interactive elements - const target = e.target as HTMLElement; - if (target.closest("button, a, input, [role='button']")) return; - - e.preventDefault(); - toggleMaximize(); + // Double click to maximize, otherwise drag. + if (e.detail === 2) { + toggleMaximize(); + } else { + startDragging(); + } }, }; } diff --git a/packages/desktop/src-tauri/Info.plist b/packages/desktop/src-tauri/Info.plist new file mode 100644 index 000000000..343992bb6 --- /dev/null +++ b/packages/desktop/src-tauri/Info.plist @@ -0,0 +1,16 @@ + + + + + CFBundleIdentifier + dev.paseo.desktop + CFBundleName + Paseo + CFBundleShortVersionString + 0.1.0 + CFBundleVersion + 0.1.0 + NSMicrophoneUsageDescription + Paseo needs access to your microphone for voice dictation and voice mode. + + diff --git a/packages/desktop/src-tauri/capabilities/default.json b/packages/desktop/src-tauri/capabilities/default.json index 7f56aa957..7ec3a7c54 100644 --- a/packages/desktop/src-tauri/capabilities/default.json +++ b/packages/desktop/src-tauri/capabilities/default.json @@ -2,6 +2,12 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "enables the default permissions", + "remote": { + "urls": [ + "http://localhost:8081/*", + "http://127.0.0.1:8081/*" + ] + }, "windows": [ "main" ], diff --git a/packages/desktop/src-tauri/src/main.rs b/packages/desktop/src-tauri/src/main.rs index 076789b9c..8c38d1778 100644 --- a/packages/desktop/src-tauri/src/main.rs +++ b/packages/desktop/src-tauri/src/main.rs @@ -1,6 +1,12 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +// `tauri dev` runs the raw executable (`target/debug/Paseo`) on macOS (not the .app bundle), +// so we must embed an Info.plist containing `NSMicrophoneUsageDescription` for WebKit +// microphone access to trigger the OS permission prompt in dev. +#[cfg(all(target_os = "macos", debug_assertions))] +tauri::embed_plist::embed_info_plist!("../Info.plist"); + fn main() { paseo_lib::run(); } diff --git a/packages/desktop/src-tauri/tauri.conf.json b/packages/desktop/src-tauri/tauri.conf.json index 848b97460..d357f33ac 100644 --- a/packages/desktop/src-tauri/tauri.conf.json +++ b/packages/desktop/src-tauri/tauri.conf.json @@ -36,6 +36,9 @@ "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico" - ] + ], + "macOS": { + "infoPlist": "Info.plist" + } } }