use crate::{
api::{assets::Assets, config::WindowUrl},
hooks::{InvokeHandler, InvokeMessage, OnPageLoad, PageLoadPayload, SetupHook},
plugin::{Plugin, PluginStore},
runtime::{
flavors::wry::Wry, manager::WindowManager, tag::Tag, webview::Attributes,
window::PendingWindow, Dispatch, Runtime,
},
sealed::{ManagerBase, RuntimeOrDispatch},
Context, Manager, Params, Window,
};
use crate::runtime::manager::Args;
#[cfg(feature = "updater")]
use crate::updater;
pub struct App<P: Params> {
runtime: P::Runtime,
manager: WindowManager<P>,
}
impl<P: Params> Manager<P> for App<P> {}
impl<P: Params> ManagerBase<P> for App<P> {
fn manager(&self) -> &WindowManager<P> {
&self.manager
}
fn runtime(&mut self) -> RuntimeOrDispatch<'_, P> {
RuntimeOrDispatch::Runtime(&mut self.runtime)
}
}
#[cfg(feature = "updater")]
impl<M: Params> App<M> {
fn run_updater_dialog(&self, window: Window<M>) {
let updater_config = self.manager.config().tauri.updater.clone();
let package_info = self.manager.package_info().clone();
crate::async_runtime::spawn(async move {
updater::check_update_with_dialog(updater_config, package_info, window).await
});
}
fn listen_updater_events(&self, window: Window<M>) {
let updater_config = self.manager.config().tauri.updater.clone();
updater::listener(updater_config, self.manager.package_info().clone(), &window);
}
fn run_updater(&self, main_window: Option<Window<M>>) {
if let Some(main_window) = main_window {
let event_window = main_window.clone();
let updater_config = self.manager.config().tauri.updater.clone();
if updater_config.dialog && updater_config.active {
self.run_updater_dialog(main_window.clone());
let config = self.manager.config().tauri.updater.clone();
let package_info = self.manager.package_info().clone();
main_window.listen(
updater::EVENT_CHECK_UPDATE
.parse()
.unwrap_or_else(|_| panic!("bad label")),
move |_msg| {
let window = event_window.clone();
let package_info = package_info.clone();
let config = config.clone();
crate::async_runtime::spawn(async move {
updater::check_update_with_dialog(config, package_info, window).await
});
},
);
} else if updater_config.active {
self.listen_updater_events(main_window);
}
}
}
}
pub struct Builder<E, L, A, R>
where
E: Tag,
L: Tag,
A: Assets,
R: Runtime,
{
invoke_handler: Box<InvokeHandler<Args<E, L, A, R>>>,
setup: SetupHook<Args<E, L, A, R>>,
on_page_load: Box<OnPageLoad<Args<E, L, A, R>>>,
pending_windows: Vec<PendingWindow<Args<E, L, A, R>>>,
plugins: PluginStore<Args<E, L, A, R>>,
}
impl<E, L, A, R> Builder<E, L, A, R>
where
E: Tag,
L: Tag,
A: Assets,
R: Runtime,
{
pub fn new() -> Self {
Self {
setup: Box::new(|_| Ok(())),
invoke_handler: Box::new(|_| ()),
on_page_load: Box::new(|_, _| ()),
pending_windows: Default::default(),
plugins: PluginStore::default(),
}
}
pub fn invoke_handler<F>(mut self, invoke_handler: F) -> Self
where
F: Fn(InvokeMessage<Args<E, L, A, R>>) + Send + Sync + 'static,
{
self.invoke_handler = Box::new(invoke_handler);
self
}
pub fn setup<F>(mut self, setup: F) -> Self
where
F: Fn(&mut App<Args<E, L, A, R>>) -> Result<(), Box<dyn std::error::Error>> + Send + 'static,
{
self.setup = Box::new(setup);
self
}
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
where
F: Fn(Window<Args<E, L, A, R>>, PageLoadPayload) + Send + Sync + 'static,
{
self.on_page_load = Box::new(on_page_load);
self
}
pub fn plugin<P: Plugin<Args<E, L, A, R>> + 'static>(mut self, plugin: P) -> Self {
self.plugins.register(plugin);
self
}
pub fn create_window<F>(mut self, label: L, url: WindowUrl, setup: F) -> Self
where
F: FnOnce(<R::Dispatcher as Dispatch>::Attributes) -> <R::Dispatcher as Dispatch>::Attributes,
{
let attributes = setup(<R::Dispatcher as Dispatch>::Attributes::new());
self
.pending_windows
.push(PendingWindow::new(attributes, label, url));
self
}
pub fn run(mut self, context: Context<A>) -> crate::Result<()> {
let manager = WindowManager::with_handlers(
context,
self.plugins,
self.invoke_handler,
self.on_page_load,
);
for config in manager.config().tauri.windows.clone() {
let url = config.url.clone();
let label = config
.label
.parse()
.unwrap_or_else(|_| panic!("bad label found in config: {}", config.label));
self
.pending_windows
.push(PendingWindow::with_config(config, label, url));
}
manager.initialize_plugins()?;
let mut app = App {
runtime: R::new()?,
manager,
};
let pending_labels = self
.pending_windows
.iter()
.map(|p| p.label.clone())
.collect::<Vec<_>>();
#[cfg(feature = "updater")]
let mut main_window = None;
for pending in self.pending_windows {
let pending = app.manager.prepare_window(pending, &pending_labels)?;
let detached = app.runtime.create_window(pending)?;
let _window = app.manager.attach_window(detached);
#[cfg(feature = "updater")]
if main_window.is_none() {
main_window = Some(_window);
}
}
#[cfg(feature = "updater")]
app.run_updater(main_window);
(self.setup)(&mut app)?;
app.runtime.run();
Ok(())
}
}
impl<A: Assets> Default for Builder<String, String, A, Wry> {
fn default() -> Self {
Self::new()
}
}