use std::path::PathBuf;
use std::sync::{Arc, OnceLock};
#[derive(Clone, Debug, Default)]
pub struct FileFilter {
pub name: String,
pub extensions: Vec<String>,
}
impl FileFilter {
pub fn new(name: impl Into<String>, extensions: &[&str]) -> Self {
Self {
name: name.into(),
extensions: extensions.iter().map(|e| (*e).to_string()).collect(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct FileDialog {
pub title: Option<String>,
pub directory: Option<PathBuf>,
pub file_name: Option<String>,
pub filters: Vec<FileFilter>,
}
impl FileDialog {
pub fn new() -> Self {
Self::default()
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn directory(mut self, dir: impl Into<PathBuf>) -> Self {
self.directory = Some(dir.into());
self
}
pub fn file_name(mut self, name: impl Into<String>) -> Self {
self.file_name = Some(name.into());
self
}
pub fn filter(mut self, name: impl Into<String>, extensions: &[&str]) -> Self {
self.filters.push(FileFilter::new(name, extensions));
self
}
}
pub trait FileDialogs: Send + Sync + 'static {
fn open_file(&self, request: FileDialog) -> Option<PathBuf>;
fn open_files(&self, request: FileDialog) -> Vec<PathBuf>;
fn save_file(&self, request: FileDialog) -> Option<PathBuf>;
fn pick_folder(&self, request: FileDialog) -> Option<PathBuf>;
}
static DIALOGS: OnceLock<Arc<dyn FileDialogs>> = OnceLock::new();
pub fn set_file_dialogs(provider: Arc<dyn FileDialogs>) {
let _ = DIALOGS.set(provider);
}
pub fn file_dialogs() -> Option<Arc<dyn FileDialogs>> {
DIALOGS.get().cloned()
}