use serde_json::Value as JsonValue;
use tauri::{webview::PageLoadPayload, AppHandle, RunEvent, Runtime, Url, Webview, Window};
use super::{
KanamaruPlugin, OnDrop, OnEvent, OnNavigation, OnPageLoad, OnWebviewReady, OnWindowReady,
SetupHook,
};
use crate::{Responder, Routes};
#[derive(Debug, Clone, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum BuilderError {
#[error("plugin uses reserved name: {0}")]
ReservedName(String),
}
const RESERVED_PLUGIN_NAMES: &[&str] = &["core", "tauri"];
pub struct Builder<R: Runtime> {
routes: Routes<R>,
name: &'static str,
setup: Option<Box<SetupHook<R>>>,
js_init_script: Option<String>,
on_page_load: Box<OnPageLoad<R>>,
on_webview_ready: Box<OnWebviewReady<R>>,
on_event: Box<OnEvent<R>>,
on_drop: Option<Box<OnDrop<R>>>,
on_window_ready: Box<OnWindowReady<R>>,
on_navigation: Box<OnNavigation<R>>,
}
impl<R> Builder<R>
where
R: Runtime,
{
pub fn new(name: &'static str) -> Self {
Self {
name,
setup: None,
js_init_script: None,
on_page_load: Box::new(|_, _| ()),
on_webview_ready: Box::new(|_| ()),
on_event: Box::new(|_, _| ()),
on_drop: None,
on_window_ready: Box::new(|_| ()),
on_navigation: Box::new(|_, _| true),
routes: Routes::default(),
}
}
#[must_use]
pub fn js_init_script(mut self, js_init_script: String) -> Self {
self.js_init_script = Some(js_init_script);
self
}
#[must_use]
pub fn setup<F>(mut self, setup: F) -> Self
where
F: FnOnce(
&AppHandle<R>,
JsonValue,
&mut Routes<R>,
) -> Result<(), Box<dyn std::error::Error>>
+ Send
+ 'static,
{
self.setup.replace(Box::new(setup));
self
}
#[must_use]
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
where
F: FnMut(&Webview<R>, &PageLoadPayload<'_>) + Send + 'static,
{
self.on_page_load = Box::new(on_page_load);
self
}
#[must_use]
pub fn on_webview_ready<F>(mut self, on_webview_ready: F) -> Self
where
F: FnMut(Webview<R>) + Send + 'static,
{
self.on_webview_ready = Box::new(on_webview_ready);
self
}
#[must_use]
pub fn on_event<F>(mut self, on_event: F) -> Self
where
F: FnMut(&AppHandle<R>, &RunEvent) + Send + 'static,
{
self.on_event = Box::new(on_event);
self
}
#[must_use]
pub fn on_drop<F>(mut self, on_drop: F) -> Self
where
F: FnOnce(AppHandle<R>) + Send + 'static,
{
self.on_drop.replace(Box::new(on_drop));
self
}
#[must_use]
pub fn on_navigation<F>(mut self, on_navigation: F) -> Self
where
F: Fn(&Webview<R>, &Url) -> bool + Send + 'static,
{
self.on_navigation = Box::new(on_navigation);
self
}
#[must_use]
pub fn on_window_ready<F>(mut self, on_window_ready: F) -> Self
where
F: FnMut(Window<R>) + Send + 'static,
{
self.on_window_ready = Box::new(on_window_ready);
self
}
pub fn add_route(mut self, responder: impl Responder<R> + Send + Sync + 'static) -> Self {
self.routes = self.routes.add_responder(responder);
self
}
pub fn try_build(self) -> Result<KanamaruPlugin<R>, BuilderError> {
if let Some(&reserved) = RESERVED_PLUGIN_NAMES.iter().find(|&r| r == &self.name) {
return Err(BuilderError::ReservedName(reserved.into()));
}
Ok(KanamaruPlugin {
name: self.name,
app: None,
setup: self.setup,
js_init_script: self.js_init_script,
on_page_load: self.on_page_load,
on_webview_ready: self.on_webview_ready,
on_event: self.on_event,
on_drop: self.on_drop,
on_navigation: self.on_navigation,
on_window_ready: self.on_window_ready,
routes: self.routes,
})
}
pub fn build(self) -> KanamaruPlugin<R> {
self.try_build().unwrap()
}
}