use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use crate::element_handle::ElementHandle;
use crate::error::Result;
use crate::options::{InputFiles, SetInputFilesOptions};
use crate::page::Page;
#[derive(Clone)]
pub struct FileChooser {
pub(crate) inner: Arc<FileChooserState>,
}
pub(crate) struct FileChooserState {
element: ElementHandle,
is_multiple: bool,
}
impl FileChooser {
#[must_use]
pub fn new(element: ElementHandle, is_multiple: bool) -> Self {
Self {
inner: Arc::new(FileChooserState { element, is_multiple }),
}
}
#[must_use]
pub fn element(&self) -> &ElementHandle {
&self.inner.element
}
#[must_use]
pub fn is_multiple(&self) -> bool {
self.inner.is_multiple
}
#[must_use]
pub fn page(&self) -> &Arc<Page> {
self.inner.element.page()
}
pub async fn set_files(&self, files: InputFiles, opts: Option<SetInputFilesOptions>) -> Result<()> {
self.inner.element.set_input_files(files, opts).await
}
}
impl std::fmt::Debug for FileChooser {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FileChooser")
.field("is_multiple", &self.inner.is_multiple)
.field("element", &self.inner.element)
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileChooserHandlerId(pub u64);
pub type FileChooserHandlerFn = Arc<dyn Fn(&FileChooser) -> bool + Send + Sync>;
struct FileChooserHandlerEntry {
id: u64,
handler: FileChooserHandlerFn,
}
#[derive(Clone, Default)]
pub struct FileChooserManager {
inner: Arc<FileChooserManagerState>,
}
#[derive(Default)]
struct FileChooserManagerState {
handlers: std::sync::Mutex<Vec<FileChooserHandlerEntry>>,
next_id: AtomicU64,
}
impl FileChooserManager {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add_handler(&self, handler: FileChooserHandlerFn) -> FileChooserHandlerId {
let id = self.inner.next_id.fetch_add(1, Ordering::Relaxed);
if let Ok(mut handlers) = self.inner.handlers.lock() {
handlers.push(FileChooserHandlerEntry { id, handler });
}
FileChooserHandlerId(id)
}
pub fn remove_handler(&self, id: FileChooserHandlerId) {
if let Ok(mut handlers) = self.inner.handlers.lock() {
handlers.retain(|h| h.id != id.0);
}
}
pub fn did_open(&self, chooser: &FileChooser) {
let handlers: Vec<FileChooserHandlerFn> = match self.inner.handlers.lock() {
Ok(g) => g.iter().map(|e| Arc::clone(&e.handler)).collect(),
Err(_) => Vec::new(),
};
let mut claimed = false;
for h in handlers {
if h(chooser) {
claimed = true;
}
}
if !claimed {
let element = chooser.inner.element.clone();
tokio::spawn(async move {
let _ = element.dispose().await;
});
}
}
#[must_use]
pub fn register_emitter_bridge(&self, events: crate::events::EventEmitter) -> FileChooserHandlerId {
self.add_handler(Arc::new(move |chooser: &FileChooser| {
if events.has_listener("filechooser") {
events.emit(crate::events::PageEvent::FileChooser(chooser.clone()));
true
} else {
false
}
}))
}
}