feat(tauri) add splashscreen API (#400)

* feat(tauri) add splashscreen API

* fix(examples) quasar example building
This commit is contained in:
Lucas Fernandes Nogueira 2020-02-08 12:34:15 -03:00 committed by GitHub
parent a572fb3dc7
commit 3e1ce404f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 34 deletions

View File

@ -18,6 +18,20 @@
* and also whitelist them based upon the developer's settings.
*/
// makes the window.external.invoke API available after window.location.href changes
if (navigator.platform != "Win64" && navigator.plaform != "Win32") {
window.external = this
if (navigator.platform == "MacIntel") {
invoke = function (x) {
webkit.messageHandlers.invoke.postMessage(x);
}
} else {
invoke = function (x) {
window.webkit.messageHandlers.external.postMessage(x);
}
}
}
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)

View File

@ -13,8 +13,8 @@ use std::io::BufRead;
fn main() {
tauri::AppBuilder::new()
.setup(|_webview| {
let handle1 = _webview.handle();
.setup(|webview, _| {
let handle1 = webview.handle();
std::thread::spawn(move || {
let resource_dir = tauri::api::platform::resource_dir().expect("failed to get resource dir");
let node_package_path = resource_dir.join("resources/packaged-node.js");
@ -35,7 +35,7 @@ fn main() {
});
});
let handle2 = _webview.handle();
let handle2 = webview.handle();
tauri::event::listen(String::from("hello"), move |msg| {
#[derive(Serialize)]
pub struct Reply {

View File

@ -6,7 +6,8 @@ mod runner;
pub struct App {
invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>, String)>>,
splashscreen_html: Option<String>,
}
impl App {
@ -23,19 +24,24 @@ impl App {
}
}
pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>) {
pub(crate) fn run_setup(&mut self, webview: &mut WebView<'_, ()>, source: String) {
match self.setup {
Some(ref mut setup) => {
setup(webview);
setup(webview, source);
}
None => {}
}
}
pub fn splashscreen_html(&self) -> Option<&String> {
self.splashscreen_html.as_ref()
}
}
pub struct AppBuilder {
invoke_handler: Option<Box<dyn FnMut(&mut WebView<'_, ()>, &str)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>)>>,
setup: Option<Box<dyn FnMut(&mut WebView<'_, ()>, String)>>,
splashscreen_html: Option<String>
}
impl AppBuilder {
@ -43,6 +49,7 @@ impl AppBuilder {
Self {
invoke_handler: None,
setup: None,
splashscreen_html: None,
}
}
@ -54,15 +61,21 @@ impl AppBuilder {
self
}
pub fn setup<F: FnMut(&mut WebView<'_, ()>) + 'static>(mut self, setup: F) -> Self {
pub fn setup<F: FnMut(&mut WebView<'_, ()>, String) + 'static>(mut self, setup: F) -> Self {
self.setup = Some(Box::new(setup));
self
}
pub fn splashscreen_html(mut self, html: &str) -> Self {
self.splashscreen_html = Some(html.to_string());
self
}
pub fn build(self) -> App {
App {
invoke_handler: self.invoke_handler,
setup: self.setup,
splashscreen_html: self.splashscreen_html,
}
}
}

View File

@ -35,12 +35,12 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
let config = get()?;
// setup the content using the config struct depending on the compile target
let content = setup_content(config.clone())?;
let main_content = setup_content(config.clone())?;
// setup the server url for the embedded-server
#[cfg(feature = "embedded-server")]
let server_url = {
if let Content::Url(ref url) = &content {
if let Content::Url(ref url) = &main_content {
String::from(url)
} else {
String::from("")
@ -48,8 +48,16 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
};
// build the webview
let mut webview = build_webview(application, config, content)?;
webview.set_color((255, 255, 255));
let webview = build_webview(
application,
config,
main_content,
if application.splashscreen_html().is_some() {
Some(Content::Html(application.splashscreen_html().expect("failed to get splashscreen_html").to_string()))
} else {
None
},
)?;
// on dev-server grab a handler and execute the tauri.js API entry point.
#[cfg(feature = "dev-server")]
@ -172,7 +180,12 @@ fn build_webview(
application: &mut App,
config: Config,
content: Content<String>,
splashscreen_content: Option<Content<String>>
) -> crate::Result<WebView<'_, ()>> {
let content_clone = match content {
Content::Html(ref html) => Content::Html(html.clone()),
Content::Url(ref url) => Content::Url(url.clone()),
};
let debug = cfg!(debug_assertions);
// get properties from config struct
let width = config.tauri.window.width;
@ -180,28 +193,54 @@ fn build_webview(
let resizable = config.tauri.window.resizable;
let title = config.tauri.window.title.into_boxed_str();
Ok(
builder()
.title(Box::leak(title))
.size(width, height)
.resizable(resizable)
.debug(debug)
.user_data(())
.invoke_handler(move |webview, arg| {
if arg == r#"{"cmd":"__initialized"}"# {
application.run_setup(webview);
webview.eval(JS_STRING)?;
} else if let Ok(b) = crate::endpoints::handle(webview, arg) {
if !b {
application.run_invoke_handler(webview, arg);
}
}
let has_splashscreen = splashscreen_content.is_some();
let mut initialized_splashscreen = false;
Ok(())
})
.content(content)
.build()?,
)
let webview = builder()
.title(Box::leak(title))
.size(width, height)
.resizable(resizable)
.debug(debug)
.user_data(())
.invoke_handler(move |webview, arg| {
if arg == r#"{"cmd":"__initialized"}"# {
let source = if has_splashscreen && !initialized_splashscreen {
initialized_splashscreen = true;
"splashscreen"
} else {
"window-1"
};
application.run_setup(webview, source.to_string());
webview.eval(JS_STRING)?;
} else if arg == r#"{"cmd":"closeSplashscreen"}"# {
let content_href = match content_clone {
Content::Html(ref html) => html,
Content::Url(ref url) => url,
};
webview.eval(&format!("window.location.href = `{}`", content_href))?;
} else if let Ok(b) = crate::endpoints::handle(webview, arg) {
if !b {
application.run_invoke_handler(webview, arg);
}
}
Ok(())
})
.content(if splashscreen_content.is_some() {
splashscreen_content.expect("failed to get splashscreen content")
} else {
content
})
.build()?;
if has_splashscreen {
// trigger the init hook for the splashscreen since we're not injecting the tauri.js entry point
webview.handle().dispatch(|webview| {
webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "__initialized" }))"#)
}).expect("failed to initialize splashscreen");
}
Ok(webview)
}
#[cfg(test)]

View File

@ -36,7 +36,7 @@ use threadpool::ThreadPool;
use error_chain::error_chain;
pub use app::*;
use web_view::WebView;
use web_view::{WebView, Handle};
pub use tauri_api as api;
@ -106,6 +106,14 @@ pub fn call<T: 'static>(
);
}
pub fn close_splashscreen<T: 'static>(webview_handle: &Handle<T>) -> crate::Result<()> {
webview_handle.dispatch(|webview| {
// send a signal to the runner so it knows that it should redirect to the main app content
webview.eval(r#"window.external.invoke(JSON.stringify({ cmd: "closeSplashscreen" }))"#)
})?;
Ok(())
}
#[cfg(test)]
mod test {
use proptest::prelude::*;