#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unreachable_pub
)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
#![cfg(not(any(target_os = "android", target_os = "ios")))]
use std::{path::PathBuf, sync::Arc, time::Duration};
use tauri::{Manager, RunEvent, Runtime, plugin::TauriPlugin};
use tauri_ui_inspector_core::{ElementReference, RedactionConfig};
mod capture;
mod commands;
mod ipc;
mod state;
use state::{PluginConfig, PluginState};
pub const EVENT_PICK_REQUESTED: &str = "ui-inspector://pick";
pub const EVENT_RESOLVE_REQUESTED: &str = "ui-inspector://resolve";
pub const EVENT_SELECTED: &str = "ui-inspector://selected";
pub const EVENT_CANCELLED: &str = "ui-inspector://cancelled";
pub type ReferenceCallback = Arc<dyn Fn(&ElementReference) + Send + Sync + 'static>;
#[derive(Clone)]
pub struct Builder {
config: PluginConfig,
callback: Option<ReferenceCallback>,
}
impl std::fmt::Debug for Builder {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Builder")
.field("config", &self.config)
.field("callback", &self.callback.as_ref().map(|_| "configured"))
.finish()
}
}
impl Builder {
#[must_use = "a plugin builder must be configured or built"]
pub fn new() -> Self {
Self {
config: PluginConfig::new(),
callback: None,
}
}
pub fn storage_dir(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.config.storage_dir = path.into();
self
}
pub fn project_root(&mut self, path: impl Into<PathBuf>) -> &mut Self {
self.config.project_root = Some(path.into());
self
}
pub fn max_history(&mut self, max_history: usize) -> &mut Self {
self.config.max_history = max_history;
self
}
pub fn crop_padding(&mut self, padding: u32) -> &mut Self {
self.config.crop_padding = padding;
self
}
pub fn capture_screenshots(&mut self, enabled: bool) -> &mut Self {
self.config.capture_screenshots = enabled;
self
}
pub fn persist_references(&mut self, enabled: bool) -> &mut Self {
self.config.persist_references = enabled;
self
}
pub fn enable_in_production(&mut self, enabled: bool) -> &mut Self {
self.config.enable_in_production = enabled;
self
}
pub fn request_timeout(&mut self, timeout: Duration) -> &mut Self {
self.config.request_timeout = timeout;
self
}
pub fn redaction(&mut self, config: RedactionConfig) -> &mut Self {
self.config.redaction = config;
self
}
pub fn on_reference_created<F>(&mut self, callback: F) -> &mut Self
where
F: Fn(&ElementReference) + Send + Sync + 'static,
{
self.callback = Some(Arc::new(callback));
self
}
#[must_use = "the returned Tauri plugin must be installed"]
pub fn build<R: Runtime>(&self) -> TauriPlugin<R> {
let config = self.config.clone();
let callback = self.callback.clone();
tauri::plugin::Builder::new("ui-inspector")
.invoke_handler(tauri::generate_handler![
commands::capture_selection,
commands::cancel_selection,
commands::complete_resolution,
commands::get_last_reference,
])
.setup(move |app, _api| {
let state = PluginState::activate(config.clone(), callback.clone())?;
let enabled = state.enabled();
app.manage(state);
if enabled {
ipc::start(app.clone())?;
}
Ok(())
})
.on_event(|app, event| {
if let RunEvent::Exit = event
&& let Some(state) = app.try_state::<PluginState>()
{
state.remove_instance_file();
}
})
.build()
}
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}