@@ -136,7 +136,7 @@ fn get_executable_dir() -> String {
|
||||
|
||||
#[derive(Clone, serde::Serialize)]
|
||||
#[allow(dead_code)]
|
||||
struct Payload {
|
||||
struct SingleInstancePayload {
|
||||
args: Vec<String>,
|
||||
cwd: String,
|
||||
}
|
||||
@@ -179,7 +179,7 @@ pub fn run() {
|
||||
if !files.is_empty() {
|
||||
allow_file_in_scopes(app, files.clone());
|
||||
}
|
||||
app.emit("single-instance", Payload { args: argv, cwd })
|
||||
app.emit("single-instance", SingleInstancePayload { args: argv, cwd })
|
||||
.unwrap();
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
use crate::allow_file_in_scopes;
|
||||
use std::path::PathBuf;
|
||||
use tauri::menu::MenuEvent;
|
||||
use tauri::menu::{SubmenuBuilder, HELP_SUBMENU_ID};
|
||||
use tauri::menu::{MenuItemBuilder, SubmenuBuilder, HELP_SUBMENU_ID};
|
||||
use tauri::AppHandle;
|
||||
use tauri::Emitter;
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
#[derive(Clone, serde::Serialize)]
|
||||
#[allow(dead_code)]
|
||||
struct OpenFilesPayload {
|
||||
files: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn setup_macos_menu(app: &AppHandle) -> tauri::Result<()> {
|
||||
let global_menu = app.menu().unwrap();
|
||||
|
||||
@@ -10,6 +19,23 @@ pub fn setup_macos_menu(app: &AppHandle) -> tauri::Result<()> {
|
||||
global_menu.remove(&item)?;
|
||||
}
|
||||
|
||||
let open_item = MenuItemBuilder::new("Open...")
|
||||
.id("open_file")
|
||||
.accelerator("Cmd+O")
|
||||
.build(app)?;
|
||||
|
||||
if let Some(file_menu) = global_menu.items()?.iter().find(|item| {
|
||||
if let Some(submenu) = item.as_submenu() {
|
||||
submenu.text().ok().as_deref() == Some("File")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
if let Some(file_submenu) = file_menu.as_submenu() {
|
||||
file_submenu.insert(&open_item, 0)?;
|
||||
}
|
||||
}
|
||||
|
||||
global_menu.append(
|
||||
&SubmenuBuilder::new(app, "Help")
|
||||
.text("privacy_policy", "Privacy Policy")
|
||||
@@ -28,7 +54,9 @@ 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 event.id() == "open_file" {
|
||||
handle_open_file(app);
|
||||
} else if event.id() == "privacy_policy" {
|
||||
let _ = opener.open_url("https://readest.com/privacy-policy", None::<&str>);
|
||||
} else if event.id() == "report_issue" {
|
||||
let _ = opener.open_url("https://github.com/readest/readest/issues", None::<&str>);
|
||||
@@ -36,3 +64,25 @@ pub fn handle_menu_event(app: &AppHandle, event: &MenuEvent) {
|
||||
let _ = opener.open_url("https://readest.com/support", None::<&str>);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_open_file(app: &AppHandle) {
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
|
||||
let app_handle = app.clone();
|
||||
|
||||
app.dialog()
|
||||
.file()
|
||||
.add_filter(
|
||||
"Files",
|
||||
&["epub", "pdf", "mobi", "azw", "azw3", "fb2", "cbz", "txt"],
|
||||
)
|
||||
.pick_file(move |file_path| {
|
||||
if let Some(path) = file_path {
|
||||
let payload = OpenFilesPayload {
|
||||
files: vec![path.to_string()],
|
||||
};
|
||||
allow_file_in_scopes(&app_handle, vec![PathBuf::from(path.to_string())]);
|
||||
let _ = app_handle.emit("open-files", payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const DEFAULT_SHORTCUTS = {
|
||||
onWikipediaSelection: ['ctrl+w', 'cmd+w'],
|
||||
onReadAloudSelection: ['ctrl+r', 'cmd+r'],
|
||||
onOpenFontLayoutSettings: ['shift+f', 'ctrl+,', 'cmd+,'],
|
||||
onOpenBooks: ['ctrl+o', 'cmd+o'],
|
||||
onOpenBooks: ['ctrl+o'],
|
||||
onReloadPage: ['shift+r'],
|
||||
onToggleFullscreen: ['F11'],
|
||||
onCloseWindow: ['ctrl+w', 'cmd+w'],
|
||||
|
||||
@@ -14,6 +14,10 @@ interface SingleInstancePayload {
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
interface OpenFilesPayload {
|
||||
files: string[];
|
||||
}
|
||||
|
||||
interface SharedIntentPayload {
|
||||
urls: string[];
|
||||
}
|
||||
@@ -80,8 +84,8 @@ export function useOpenWithBooks() {
|
||||
// For Windows/Linux deep link and macOS open-file event
|
||||
const unlistenDeeplink = getCurrentWindow().listen<SingleInstancePayload>(
|
||||
'single-instance',
|
||||
({ event, payload }) => {
|
||||
console.log('Received deep link:', event, payload);
|
||||
({ payload }) => {
|
||||
console.log('Received deep link:', payload);
|
||||
const { args } = payload;
|
||||
if (args?.[1]) {
|
||||
handleOpenWithFileUrl([args[1]]);
|
||||
@@ -89,6 +93,18 @@ export function useOpenWithBooks() {
|
||||
},
|
||||
);
|
||||
|
||||
// macOS in-app open-files event
|
||||
const unlistenOpenFiles = getCurrentWindow().listen<OpenFilesPayload>(
|
||||
'open-files',
|
||||
({ payload }) => {
|
||||
console.log('Received open files:', payload);
|
||||
const { files } = payload;
|
||||
if (files && files.length > 0) {
|
||||
handleOpenWithFileUrl(files);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// For Android "Share to Readest" intent
|
||||
let unlistenSharedIntent: Promise<PluginListener> | null = null;
|
||||
// FIXME: register/unregister plugin listeniner on iOS might cause app freeze for unknown reason
|
||||
@@ -106,6 +122,7 @@ export function useOpenWithBooks() {
|
||||
const unlistenOpenUrl = listenOpenWithFiles();
|
||||
return () => {
|
||||
unlistenDeeplink.then((f) => f());
|
||||
unlistenOpenFiles.then((f) => f());
|
||||
unlistenOpenUrl.then((f) => f());
|
||||
unlistenSharedIntent?.then((f) => f.unregister());
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user