//! Native file dialogs owned by the Core (the UI never supplies local paths itself). use std::path::PathBuf; use tauri::{AppHandle, Manager, Runtime, WebviewWindow}; use tauri_plugin_dialog::{DialogExt, FileDialogBuilder, FilePath}; pub struct Filter<'a> { pub name: &'a str, pub extensions: &'a [&'a str], } fn to_path(file: FilePath) -> Option { file.into_path().ok() } fn builder(app: &AppHandle, parent: Option<&WebviewWindow>, title: Option<&str>, filters: &[Filter<'_>]) -> FileDialogBuilder { let mut builder = app.dialog().file(); if let Some(window) = parent { builder = builder.set_parent(window); } if let Some(title) = title { builder = builder.set_title(title); } for filter in filters { builder = builder.add_filter(filter.name, filter.extensions); } builder } pub fn main_window(app: &AppHandle) -> Option> { app.get_webview_window(crate::security::caller::MAIN_LABEL) } pub async fn pick_file(app: &AppHandle, parent: Option<&WebviewWindow>, title: Option<&str>, filters: &[Filter<'_>]) -> Option { let (tx, rx) = tokio::sync::oneshot::channel(); builder(app, parent, title, filters).pick_file(move |file| { let _ = tx.send(file.and_then(to_path)); }); rx.await.ok().flatten() } pub async fn pick_files(app: &AppHandle, parent: Option<&WebviewWindow>, title: Option<&str>, filters: &[Filter<'_>]) -> Vec { let (tx, rx) = tokio::sync::oneshot::channel(); builder(app, parent, title, filters).pick_files(move |files| { let _ = tx.send(files.unwrap_or_default().into_iter().filter_map(to_path).collect::>()); }); rx.await.unwrap_or_default() } pub async fn pick_folder(app: &AppHandle, parent: Option<&WebviewWindow>, title: Option<&str>) -> Option { let (tx, rx) = tokio::sync::oneshot::channel(); builder(app, parent, title, &[]).set_can_create_directories(true).pick_folder(move |folder| { let _ = tx.send(folder.and_then(to_path)); }); rx.await.ok().flatten() } pub async fn save_file(app: &AppHandle, parent: Option<&WebviewWindow>, title: Option<&str>, suggested: &str, filters: &[Filter<'_>]) -> Option { let (tx, rx) = tokio::sync::oneshot::channel(); let mut builder = builder(app, parent, title, filters); if !suggested.is_empty() { builder = builder.set_file_name(suggested); } builder.save_file(move |file| { let _ = tx.send(file.and_then(to_path)); }); rx.await.ok().flatten() }