diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9fbdbda..57fd5adb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,6 +82,13 @@ This project is a monorepo. The code for the `readest-app` is in the `app/reades | `pnpm dev-web` | Starts the development server for the web app only | | `pnpm build-web` | Builds the web app | +Recommended Visual Studio Code plugins for development: + +- JavaScript and TypeScript Nightly (ms-vscode.vscode-typescript-next) +- VS Code ESLint extension (dbaeumer.vscode-eslint) +- Prettier - Code formatter (esbenp.prettier-vscode) +- rust-analyzer (rust-lang.rust-analyzer) (for Tauri development only) + ### When you're done Check that your code follows the project's style guidelines by running: diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index 42d53ec9..01479653 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -38,6 +38,7 @@ "@tauri-apps/plugin-fs": "^2.2.0", "@tauri-apps/plugin-http": "^2.2.0", "@tauri-apps/plugin-log": "^2.2.0", + "@tauri-apps/plugin-opener": "^2.2.2", "@tauri-apps/plugin-os": "^2.2.0", "@tauri-apps/plugin-process": "^2.2.0", "@tauri-apps/plugin-shell": "~2.2.0", diff --git a/apps/readest-app/src-tauri/Cargo.lock b/apps/readest-app/src-tauri/Cargo.lock index c863735f..94025989 100644 --- a/apps/readest-app/src-tauri/Cargo.lock +++ b/apps/readest-app/src-tauri/Cargo.lock @@ -21,6 +21,7 @@ dependencies = [ "tauri-plugin-http", "tauri-plugin-log", "tauri-plugin-oauth", + "tauri-plugin-opener", "tauri-plugin-os", "tauri-plugin-process", "tauri-plugin-shell", @@ -197,7 +198,7 @@ dependencies = [ "wayland-backend", "wayland-client", "wayland-protocols", - "zbus", + "zbus 5.2.0", ] [[package]] @@ -212,6 +213,91 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + [[package]] name = "async-recursion" version = "1.1.1" @@ -223,6 +309,24 @@ dependencies = [ "syn 2.0.91", ] +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.59.0", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -245,6 +349,12 @@ dependencies = [ "syn 2.0.91", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.83" @@ -414,6 +524,19 @@ dependencies = [ "objc2", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "borsh" version = "1.5.3" @@ -1486,6 +1609,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -1898,6 +2034,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -3351,6 +3493,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.31" @@ -3383,6 +3536,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "portable-atomic" version = "1.10.0" @@ -4252,6 +4420,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -4906,6 +5085,28 @@ dependencies = [ "url", ] +[[package]] +name = "tauri-plugin-opener" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63ac39033ef1bb4d52da4878c3d8ab6d80b0a569d69208c884e6d4d54eb427b9" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.9", + "url", + "windows", + "zbus 4.4.0", +] + [[package]] name = "tauri-plugin-os" version = "2.2.0" @@ -6569,6 +6770,44 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + [[package]] name = "zbus" version = "5.2.0" @@ -6594,9 +6833,22 @@ dependencies = [ "windows-sys 0.59.0", "winnow 0.6.20", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 5.2.0", + "zbus_names 4.1.0", + "zvariant 5.1.0", +] + +[[package]] +name = "zbus_macros" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.91", + "zvariant_utils 2.1.0", ] [[package]] @@ -6609,9 +6861,20 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.91", - "zbus_names", - "zvariant", - "zvariant_utils", + "zbus_names 4.1.0", + "zvariant 5.1.0", + "zvariant_utils 3.0.2", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant 4.2.0", ] [[package]] @@ -6623,7 +6886,7 @@ dependencies = [ "serde", "static_assertions", "winnow 0.6.20", - "zvariant", + "zvariant 5.1.0", ] [[package]] @@ -6711,6 +6974,19 @@ dependencies = [ "thiserror 2.0.9", ] +[[package]] +name = "zvariant" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "zvariant_derive 4.2.0", +] + [[package]] name = "zvariant" version = "5.1.0" @@ -6723,8 +6999,21 @@ dependencies = [ "static_assertions", "url", "winnow 0.6.20", - "zvariant_derive", - "zvariant_utils", + "zvariant_derive 5.1.0", + "zvariant_utils 3.0.2", +] + +[[package]] +name = "zvariant_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.91", + "zvariant_utils 2.1.0", ] [[package]] @@ -6737,7 +7026,18 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.91", - "zvariant_utils", + "zvariant_utils 3.0.2", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", ] [[package]] diff --git a/apps/readest-app/src-tauri/Cargo.toml b/apps/readest-app/src-tauri/Cargo.toml index 284f42da..6b7dfe36 100644 --- a/apps/readest-app/src-tauri/Cargo.toml +++ b/apps/readest-app/src-tauri/Cargo.toml @@ -33,6 +33,7 @@ tauri-plugin-devtools = "2.0.0" tauri-plugin-shell = "2" tauri-plugin-process = "2" tauri-plugin-oauth = "2" +tauri-plugin-opener = "2.2.2" [patch.crates-io] tauri = { path = "../../../packages/tauri/crates/tauri" } diff --git a/apps/readest-app/src-tauri/capabilities/default.json b/apps/readest-app/src-tauri/capabilities/default.json index 0b866036..5dfcf3fa 100644 --- a/apps/readest-app/src-tauri/capabilities/default.json +++ b/apps/readest-app/src-tauri/capabilities/default.json @@ -60,6 +60,7 @@ "process:allow-restart", "cli:default", "oauth:allow-start", - "oauth:allow-cancel" + "oauth:allow-cancel", + "opener:default" ] } diff --git a/apps/readest-app/src-tauri/src/lib.rs b/apps/readest-app/src-tauri/src/lib.rs index 1bfa41c3..880f94e0 100644 --- a/apps/readest-app/src-tauri/src/lib.rs +++ b/apps/readest-app/src-tauri/src/lib.rs @@ -77,6 +77,7 @@ pub fn run() { .plugin(tauri_plugin_oauth::init()) .invoke_handler(tauri::generate_handler![start_server]) .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_dialog::init()) diff --git a/apps/readest-app/src-tauri/src/menu.rs b/apps/readest-app/src-tauri/src/menu.rs index 65cd3321..66bbca83 100644 --- a/apps/readest-app/src-tauri/src/menu.rs +++ b/apps/readest-app/src-tauri/src/menu.rs @@ -1,7 +1,7 @@ use tauri::menu::MenuEvent; use tauri::menu::{SubmenuBuilder, HELP_SUBMENU_ID}; use tauri::AppHandle; -use tauri_plugin_shell::ShellExt; +use tauri_plugin_opener::OpenerExt; pub fn setup_macos_menu(app: &AppHandle) -> tauri::Result<()> { let global_menu = app.menu().unwrap(); @@ -27,17 +27,12 @@ pub fn setup_macos_menu(app: &AppHandle) -> tauri::Result<()> { } pub fn handle_menu_event(app: &AppHandle, event: &MenuEvent) { + let opener = app.opener(); if event.id() == "privacy_policy" { - if let Err(e) = app.shell().open("https://readest.com/privacy-policy", None) { - eprintln!("Failed to open privacy policy: {}", e); - } + let _ = opener.open_url("https://readest.com/privacy-policy", None::<&str>); } else if event.id() == "report_issue" { - if let Err(e) = app.shell().open("mailto:support@bilingify.com", None) { - eprintln!("Failed to open mail client: {}", e); - } + let _ = opener.open_url("https://github.com/readest/readest/issues", None::<&str>); } else if event.id() == "readest_help" { - if let Err(e) = app.shell().open("https://readest.com/support", None) { - eprintln!("Failed to open support page: {}", e); - } + let _ = opener.open_url("https://readest.com/support", None::<&str>); } } diff --git a/apps/readest-app/src/app/auth/page.tsx b/apps/readest-app/src/app/auth/page.tsx index aef45702..4accaa34 100644 --- a/apps/readest-app/src/app/auth/page.tsx +++ b/apps/readest-app/src/app/auth/page.tsx @@ -14,8 +14,8 @@ import { useAuth } from '@/context/AuthContext'; import { supabase } from '@/utils/supabase'; import { useTheme } from '@/hooks/useTheme'; import { isTauriAppPlatform } from '@/services/environment'; -import { open } from '@tauri-apps/plugin-shell'; import { start, cancel, onUrl, onInvalidUrl } from '@fabianlars/tauri-plugin-oauth'; +import { openUrl } from '@tauri-apps/plugin-opener'; import { handleAuthCallback } from '@/helpers/auth'; import { IoArrowBack } from 'react-icons/io5'; @@ -68,7 +68,7 @@ export default function AuthPage() { console.error('Authentication error:', error); return; } - open(data.url); + openUrl(data.url); }; const startOAuthServer = async () => { @@ -146,7 +146,10 @@ export default function AuthPage() { return isTauriAppPlatform() ? (