mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-01 10:01:07 +02:00
* on_download_started & on_download_completed setters * macos: default handler fn if not set * remove default macos handler * doc comments * unify hooks, change files --------- Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
5
.changes/on-download-hook.md
Normal file
5
.changes/on-download-hook.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:feat
|
||||
---
|
||||
|
||||
Added `WindowBuilder::on_download` to handle download request events.
|
||||
6
.changes/runtime-on-download-hooks.md
Normal file
6
.changes/runtime-on-download-hooks.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri-runtime": patch:feat
|
||||
"tauri-runtime-wry": patch:feat
|
||||
---
|
||||
|
||||
Added download event closure via `PendingWindow::download_handler`.
|
||||
@@ -17,7 +17,8 @@ use tauri_runtime::{
|
||||
webview::{WebviewIpcHandler, WindowBuilder, WindowBuilderBase},
|
||||
window::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
|
||||
CursorIcon, DetachedWindow, FileDropEvent, PendingWindow, RawWindow, WindowEvent,
|
||||
CursorIcon, DetachedWindow, DownloadEvent, FileDropEvent, PendingWindow, RawWindow,
|
||||
WindowEvent,
|
||||
},
|
||||
DeviceEventFilter, Dispatch, Error, EventLoopProxy, ExitRequestedEventAction, Icon, Result,
|
||||
RunEvent, RunIteration, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, UserEvent,
|
||||
@@ -2719,8 +2720,6 @@ fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
|
||||
label,
|
||||
ipc_handler,
|
||||
url,
|
||||
#[cfg(target_os = "android")]
|
||||
on_webview_created,
|
||||
..
|
||||
} = pending;
|
||||
|
||||
@@ -2852,6 +2851,25 @@ fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(download_handler) = pending.download_handler {
|
||||
let download_handler_ = download_handler.clone();
|
||||
webview_builder = webview_builder.with_download_started_handler(move |url, path| {
|
||||
if let Ok(url) = url.parse() {
|
||||
download_handler_(DownloadEvent::Requested {
|
||||
url,
|
||||
destination: path,
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
webview_builder = webview_builder.with_download_completed_handler(move |url, path, success| {
|
||||
if let Ok(url) = url.parse() {
|
||||
download_handler(DownloadEvent::Finished { url, path, success });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(page_load_handler) = pending.on_page_load_handler {
|
||||
webview_builder = webview_builder.with_on_page_load_handler(move |event, url| {
|
||||
let _ = Url::parse(&url).map(|url| {
|
||||
@@ -2954,7 +2972,7 @@ fn create_webview<T: UserEvent, F: Fn(RawWindow) + Send + 'static>(
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
if let Some(on_webview_created) = on_webview_created {
|
||||
if let Some(on_webview_created) = pending.on_webview_created {
|
||||
webview_builder = webview_builder.on_webview_created(move |ctx| {
|
||||
on_webview_created(tauri_runtime::window::CreationContext {
|
||||
env: ctx.env,
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::{
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
path::PathBuf,
|
||||
sync::mpsc::Sender,
|
||||
sync::{mpsc::Sender, Arc},
|
||||
};
|
||||
|
||||
use self::dpi::PhysicalPosition;
|
||||
@@ -36,6 +36,30 @@ type NavigationHandler = dyn Fn(&Url) -> bool + Send;
|
||||
|
||||
type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
|
||||
|
||||
type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync;
|
||||
|
||||
/// Download event.
|
||||
pub enum DownloadEvent<'a> {
|
||||
/// Download requested.
|
||||
Requested {
|
||||
/// The url being downloaded.
|
||||
url: Url,
|
||||
/// Represents where the file will be downloaded to.
|
||||
/// Can be used to set the download location by assigning a new path to it.
|
||||
/// The assigned path _must_ be absolute.
|
||||
destination: &'a mut PathBuf,
|
||||
},
|
||||
/// Download finished.
|
||||
Finished {
|
||||
/// The URL of the original download request.
|
||||
url: Url,
|
||||
/// Potentially representing the filesystem path the file was downloaded to.
|
||||
path: Option<PathBuf>,
|
||||
/// Indicates if the download succeeded or not.
|
||||
success: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// Kind of event for the page load handler.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PageLoadEvent {
|
||||
@@ -240,6 +264,8 @@ pub struct PendingWindow<T: UserEvent, R: Runtime<T>> {
|
||||
/// A handler to decide if incoming url is allowed to navigate.
|
||||
pub navigation_handler: Option<Box<NavigationHandler>>,
|
||||
|
||||
pub download_handler: Option<Arc<DownloadHandler>>,
|
||||
|
||||
/// The resolved URL to load on the webview.
|
||||
pub url: String,
|
||||
|
||||
@@ -284,6 +310,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
|
||||
label,
|
||||
ipc_handler: None,
|
||||
navigation_handler: None,
|
||||
download_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
#[cfg(target_os = "android")]
|
||||
on_webview_created: None,
|
||||
@@ -313,6 +340,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWindow<T, R> {
|
||||
label,
|
||||
ipc_handler: None,
|
||||
navigation_handler: None,
|
||||
download_handler: None,
|
||||
url: "tauri://localhost".to_string(),
|
||||
#[cfg(target_os = "android")]
|
||||
on_webview_created: None,
|
||||
|
||||
@@ -64,6 +64,7 @@ use std::{
|
||||
pub(crate) type WebResourceRequestHandler =
|
||||
dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
|
||||
pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send;
|
||||
pub(crate) type DownloadHandler<R> = dyn Fn(Window<R>, DownloadEvent<'_>) -> bool + Send + Sync;
|
||||
pub(crate) type UriSchemeProtocolHandler =
|
||||
Box<dyn Fn(http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>;
|
||||
pub(crate) type OnPageLoad<R> = dyn Fn(Window<R>, PageLoadPayload<'_>) + Send + Sync + 'static;
|
||||
@@ -92,6 +93,38 @@ impl<'a> PageLoadPayload<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Download event for the [`WindowBuilder#method.on_download`] hook.
|
||||
#[non_exhaustive]
|
||||
pub enum DownloadEvent<'a> {
|
||||
/// Download requested.
|
||||
Requested {
|
||||
/// The url being downloaded.
|
||||
url: Url,
|
||||
/// Represents where the file will be downloaded to.
|
||||
/// Can be used to set the download location by assigning a new path to it.
|
||||
/// The assigned path _must_ be absolute.
|
||||
destination: &'a mut PathBuf,
|
||||
},
|
||||
/// Download finished.
|
||||
Finished {
|
||||
/// The URL of the original download request.
|
||||
url: Url,
|
||||
/// Potentially representing the filesystem path the file was downloaded to.
|
||||
///
|
||||
/// A value of `None` being passed instead of a `PathBuf` does not necessarily indicate that the download
|
||||
/// did not succeed, and may instead indicate some other failure - always check the third parameter if you need to
|
||||
/// know if the download succeeded.
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **macOS**: The second parameter indicating the path the file was saved to is always empty, due to API
|
||||
/// limitations.
|
||||
path: Option<PathBuf>,
|
||||
/// Indicates if the download succeeded or not.
|
||||
success: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// Monitor descriptor.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -149,6 +182,7 @@ pub struct WindowBuilder<'a, R: Runtime> {
|
||||
pub(crate) webview_attributes: WebviewAttributes,
|
||||
web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
|
||||
navigation_handler: Option<Box<NavigationHandler>>,
|
||||
download_handler: Option<Arc<DownloadHandler<R>>>,
|
||||
on_page_load_handler: Option<Box<OnPageLoad<R>>>,
|
||||
#[cfg(desktop)]
|
||||
on_menu_event: Option<crate::app::GlobalMenuEventListener<Window<R>>>,
|
||||
@@ -228,6 +262,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
webview_attributes: WebviewAttributes::new(url),
|
||||
web_resource_request_handler: None,
|
||||
navigation_handler: None,
|
||||
download_handler: None,
|
||||
on_page_load_handler: None,
|
||||
#[cfg(desktop)]
|
||||
on_menu_event: None,
|
||||
@@ -267,6 +302,7 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
window_builder: <R::Dispatcher as Dispatch<EventLoopMessage>>::WindowBuilder::with_config(
|
||||
config,
|
||||
),
|
||||
download_handler: None,
|
||||
web_resource_request_handler: None,
|
||||
#[cfg(desktop)]
|
||||
menu: None,
|
||||
@@ -353,6 +389,47 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a download event handler to be notified when a download is requested or finished.
|
||||
///
|
||||
/// Returning `false` prevents the download from happening on a [`DownloadEvent::Requested`] event.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::{
|
||||
/// utils::config::{Csp, CspDirectiveSources, WindowUrl},
|
||||
/// window::{DownloadEvent, WindowBuilder},
|
||||
/// };
|
||||
///
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// WindowBuilder::new(app, "core", WindowUrl::App("index.html".into()))
|
||||
/// .on_download(|window, event| {
|
||||
/// match event {
|
||||
/// DownloadEvent::Requested { url, destination } => {
|
||||
/// println!("downloading {}", url);
|
||||
/// *destination = "/home/tauri/target/path".into();
|
||||
/// }
|
||||
/// DownloadEvent::Finished { url, path, success } => {
|
||||
/// println!("downloaded {} to {:?}, success: {}", url, path, success);
|
||||
/// }
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// // let the download start
|
||||
/// true
|
||||
/// })
|
||||
/// .build()?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn on_download<F: Fn(Window<R>, DownloadEvent<'_>) -> bool + Send + Sync + 'static>(
|
||||
mut self,
|
||||
f: F,
|
||||
) -> Self {
|
||||
self.download_handler.replace(Arc::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
/// Defines a closure to be executed when a page load event is triggered.
|
||||
/// The event can be either [`PageLoadEvent::Started`] if the page has started loading
|
||||
/// or [`PageLoadEvent::Finished`] when the page finishes loading.
|
||||
@@ -361,18 +438,16 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri::{
|
||||
/// utils::config::{Csp, CspDirectiveSources, WindowUrl},
|
||||
/// utils::config::WindowUrl,
|
||||
/// window::{PageLoadEvent, WindowBuilder},
|
||||
/// };
|
||||
/// use http::header::HeaderValue;
|
||||
/// use std::collections::HashMap;
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// WindowBuilder::new(app, "core", WindowUrl::App("index.html".into()))
|
||||
/// .on_page_load(|window, payload| {
|
||||
/// match payload.event() {
|
||||
/// PageLoadEvent::Started => {
|
||||
/// println!("{} finished loading", payload.url());
|
||||
/// println!("{} started loading", payload.url());
|
||||
/// }
|
||||
/// PageLoadEvent::Finished => {
|
||||
/// println!("{} finished loading", payload.url());
|
||||
@@ -444,6 +519,28 @@ impl<'a, R: Runtime> WindowBuilder<'a, R> {
|
||||
pending.navigation_handler = self.navigation_handler.take();
|
||||
pending.web_resource_request_handler = self.web_resource_request_handler.take();
|
||||
|
||||
if let Some(download_handler) = self.download_handler.take() {
|
||||
let label = pending.label.clone();
|
||||
let manager = self.app_handle.manager.clone();
|
||||
pending.download_handler.replace(Arc::new(move |event| {
|
||||
if let Some(w) = manager.get_window(&label) {
|
||||
download_handler(
|
||||
w,
|
||||
match event {
|
||||
tauri_runtime::window::DownloadEvent::Requested { url, destination } => {
|
||||
DownloadEvent::Requested { url, destination }
|
||||
}
|
||||
tauri_runtime::window::DownloadEvent::Finished { url, path, success } => {
|
||||
DownloadEvent::Finished { url, path, success }
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(on_page_load_handler) = self.on_page_load_handler.take() {
|
||||
let label = pending.label.clone();
|
||||
let manager = self.app_handle.manager.clone();
|
||||
|
||||
Reference in New Issue
Block a user