Merge remote-tracking branch 'upstream/main' into updater
3
examples/api/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
/dist/
|
||||
/target/
|
||||
/Cargo.lock
|
|
@ -1,16 +0,0 @@
|
|||
[build]
|
||||
target = "./index.html"
|
||||
|
||||
[watch]
|
||||
ignore = ["./src-tauri"]
|
||||
|
||||
[serve]
|
||||
address = "127.0.0.1"
|
||||
port = 1420
|
||||
open = false
|
||||
|
||||
# [[hooks]]
|
||||
# # Runs SSG on production builds
|
||||
# stage = "post_build"
|
||||
# command = "bash"
|
||||
# command_arguments = ["-c", "if [[ $TRUNK_PROFILE == \"release\" ]]; then cargo run --release --features ssg -- $TRUNK_STAGING_DIR; fi"]
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Tauri + Yew App</title>
|
||||
<link data-trunk rel="css" href="style.css" />
|
||||
<link data-trunk rel="copy-dir" href="public" />
|
||||
</head>
|
||||
<body>
|
||||
<!--app-html-->
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,9 +0,0 @@
|
|||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.140", features = ["derive"] }
|
|
@ -1,12 +0,0 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Reply<'a> {
|
||||
pub data: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RequestBody<'a> {
|
||||
pub id: i32,
|
||||
pub name: &'a str,
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use shared::{Reply, RequestBody};
|
||||
|
||||
#[tauri::command]
|
||||
fn log_operation(event: String, payload: Option<String>) {
|
||||
println!("{} {:?}", event, payload);
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn perform_request(endpoint: String, body: RequestBody) -> String {
|
||||
println!("{} {:?}", endpoint, body);
|
||||
"message response".into()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![log_operation, perform_request])
|
||||
.on_page_load(|window, _| {
|
||||
let window_ = window.clone();
|
||||
window.listen("js-event", move |event| {
|
||||
println!("got js-event with message '{:?}'", event.payload());
|
||||
let reply = Reply {
|
||||
data: "something else",
|
||||
};
|
||||
|
||||
window_
|
||||
.emit("rust-event", Some(reply))
|
||||
.expect("failed to emit");
|
||||
});
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
mod views;
|
||||
|
||||
use sycamore::prelude::*;
|
||||
#[cfg(not(feature = "ssg"))]
|
||||
use sycamore_router::{Router, HistoryIntegration};
|
||||
|
||||
#[component]
|
||||
fn Header<G: Html>(cx: Scope) -> View<G> {
|
||||
view! { cx,
|
||||
header(style="display: flex; gap: 1em; margin-bottom: 1em;") {
|
||||
a(href="/") {
|
||||
"Welcome"
|
||||
}
|
||||
a(href="/app") {
|
||||
"App"
|
||||
}
|
||||
a(href="/clipboard") {
|
||||
"Clipboard"
|
||||
}
|
||||
a(href="/updater") {
|
||||
"Updater"
|
||||
}
|
||||
a(href="/communication") {
|
||||
"Communication"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(debug_assertions), not(feature = "ssg")))]
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
|
||||
sycamore::hydrate(|cx| view! { cx,
|
||||
Header
|
||||
Router(
|
||||
integration=HistoryIntegration::new(),
|
||||
view=views::switch
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(all(debug_assertions, not(feature = "ssg")))]
|
||||
fn main() {
|
||||
use sycamore::view;
|
||||
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
|
||||
sycamore::render(|cx| view! { cx,
|
||||
Header
|
||||
Router(
|
||||
integration=HistoryIntegration::new(),
|
||||
view=views::switch
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssg")]
|
||||
fn main() {
|
||||
use sycamore_router::StaticRouter;
|
||||
|
||||
let out_dir = std::env::args().nth(1).unwrap();
|
||||
|
||||
println!("out_dir {}", out_dir);
|
||||
|
||||
let template = std::fs::read_to_string(format!("{}/index.html", out_dir)).unwrap();
|
||||
|
||||
let html = sycamore::render_to_string(|cx| view! { cx,
|
||||
Header
|
||||
StaticRouter(
|
||||
route=route.clone(),
|
||||
view=views::switch
|
||||
)
|
||||
});
|
||||
|
||||
let html = template.replace("<!--app-html-->\n", &html);
|
||||
|
||||
let path = format!("{}/index.html", out_dir);
|
||||
|
||||
println!("Writing html to file \"{}\"", path);
|
||||
std::fs::write(path, html).unwrap();
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
use gloo_timers::callback::Timeout;
|
||||
use sycamore::prelude::*;
|
||||
use tauri_sys::app;
|
||||
|
||||
#[component]
|
||||
pub fn App<G: Html>(cx: Scope) -> View<G> {
|
||||
let show_app = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::hide().await;
|
||||
|
||||
log::debug!("app hide res {:?}", res);
|
||||
|
||||
let timeout = Timeout::new(2_000, move || {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::show().await;
|
||||
|
||||
log::debug!("app show res {:?}", res);
|
||||
});
|
||||
});
|
||||
|
||||
timeout.forget();
|
||||
});
|
||||
};
|
||||
|
||||
let hide_app = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::hide().await;
|
||||
|
||||
log::debug!("app hide res {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
let get_name = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::get_name().await;
|
||||
|
||||
log::debug!("app name {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
let get_version = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::get_version().await;
|
||||
|
||||
log::debug!("app version {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
let get_tauri_version = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = app::get_tauri_version().await;
|
||||
|
||||
log::debug!("tauri version {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
div {
|
||||
button(class="btn",id="get_name",on:click=get_name) {
|
||||
"Get App Name"
|
||||
}
|
||||
button(class="btn",id="get_version",on:click=get_version) {
|
||||
"Get App Version"
|
||||
}
|
||||
button(class="btn",id="get_tauri_version",on:click=get_tauri_version) {
|
||||
"Get Tauri Version"
|
||||
}
|
||||
}
|
||||
div {
|
||||
button(class="btn",id="show",title="Hides and shows the app after 2 seconds",on:click=show_app) {
|
||||
"Show"
|
||||
}
|
||||
button(class="btn",id="hide",on:click=hide_app) {
|
||||
"Hide"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
use sycamore::prelude::*;
|
||||
use tauri_sys::clipboard::{read_text, write_text};
|
||||
|
||||
#[component]
|
||||
pub fn Clipboard<G: Html>(cx: Scope) -> View<G> {
|
||||
let text = create_signal(cx, "clipboard message".to_string());
|
||||
|
||||
let write = move |_| {
|
||||
sycamore::futures::spawn_local_scoped(cx, async move {
|
||||
write_text(&text.get()).await
|
||||
// .then(() => {
|
||||
// onMessage('Wrote to the clipboard')
|
||||
// })
|
||||
// .catch(onMessage)
|
||||
});
|
||||
};
|
||||
|
||||
let read = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let text = read_text().await;
|
||||
|
||||
log::info!("Read text from clipboard {:?}", text);
|
||||
// readText()
|
||||
// .then((contents) => {
|
||||
// onMessage(`Clipboard contents: ${contents}`)
|
||||
// })
|
||||
// .catch(onMessage)
|
||||
});
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
div(class="flex gap-1") {
|
||||
input(class="grow input",placeholder="Text to write to the clipboard",bind:value=text)
|
||||
button(class="btn",type="button",on:click=write) {
|
||||
"Write"
|
||||
}
|
||||
button(class="btn",type="button",on:click=read) {
|
||||
"Read"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sycamore::prelude::*;
|
||||
use tauri_sys::event::{emit, listen};
|
||||
use tauri_sys::tauri::invoke;
|
||||
use shared::RequestBody;
|
||||
|
||||
#[component]
|
||||
pub fn Communication<'a, G: Html>(cx: Scope<'a>) -> View<G> {
|
||||
let unlisten = create_signal::<Option<Box<&dyn FnOnce()>>>(cx, None);
|
||||
|
||||
// on_mount(cx, move || {
|
||||
|
||||
// sycamore::futures::spawn_local_scoped(cx, async move {
|
||||
// let unlisten_raw = listen::<Reply>("rust-event", &|reply| log::debug!("got reply {:?}", reply)).await;
|
||||
|
||||
// unlisten.set(Some(Box::new(&unlisten_raw)));
|
||||
// });
|
||||
// });
|
||||
|
||||
// on_cleanup(cx, || {
|
||||
// if let Some(unlisten) = unlisten .take().as_deref() {
|
||||
// (unlisten)()
|
||||
// }
|
||||
// });
|
||||
|
||||
let log = |_| {
|
||||
#[derive(Serialize)]
|
||||
struct Payload<'a> {
|
||||
event: &'a str,
|
||||
payload: &'a str,
|
||||
}
|
||||
|
||||
sycamore::futures::spawn_local(async move {
|
||||
let res = invoke::<_, ()>(
|
||||
"log_operation",
|
||||
&Payload {
|
||||
event: "tauri-click",
|
||||
payload: "this payload is optional because we used Option in Rust",
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
log::debug!("Emitted event, response {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
let perform_request = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
#[derive(Serialize)]
|
||||
struct Payload<'a> {
|
||||
endpoint: &'a str,
|
||||
body: RequestBody<'a>
|
||||
}
|
||||
|
||||
let res = invoke::<_, String>(
|
||||
"perform_request",
|
||||
&Payload {
|
||||
endpoint: "dummy endpoint arg",
|
||||
body: RequestBody {
|
||||
id: 5,
|
||||
name: "test",
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
log::debug!("Got reply {:?}", res);
|
||||
});
|
||||
};
|
||||
|
||||
let emit_event = |_| {
|
||||
sycamore::futures::spawn_local(async move {
|
||||
emit("js-event", &"this is the payload string").await;
|
||||
});
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
div {
|
||||
button(class="btn",id="log",on:click=log) {
|
||||
"Call Log API"
|
||||
}
|
||||
button(class="btn",mid="request",on:click=perform_request) {
|
||||
"Call Request (async) API"
|
||||
}
|
||||
button(class="btn",id="event",on:click=emit_event) {
|
||||
"Send event to Rust"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
mod app;
|
||||
mod clipboard;
|
||||
mod communication;
|
||||
mod updater;
|
||||
mod welcome;
|
||||
|
||||
use sycamore::view::View;
|
||||
use sycamore_router::Route;
|
||||
use sycamore::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Route)]
|
||||
pub enum Page {
|
||||
#[to("/app")]
|
||||
App,
|
||||
#[to("/clipboard")]
|
||||
Clipboard,
|
||||
#[to("/communication")]
|
||||
Communication,
|
||||
#[to("/updater")]
|
||||
Updater,
|
||||
#[not_found]
|
||||
NotFound
|
||||
}
|
||||
|
||||
pub fn switch<G: Html>(cx: Scope, route: &ReadSignal<Page>) -> View<G> {
|
||||
match route.get().as_ref() {
|
||||
Page::App => app::App(cx),
|
||||
Page::Clipboard => clipboard::Clipboard(cx),
|
||||
Page::Communication => communication::Communication(cx),
|
||||
Page::Updater => updater::Updater(cx),
|
||||
Page::NotFound => welcome::Welcome(cx)
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
use sycamore::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn Welcome<G: Html>(cx: Scope) -> View<G> {
|
||||
view! { cx,
|
||||
h1 {
|
||||
"Welcome"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
.logo.yew:hover {
|
||||
filter: drop-shadow(0 0 2em #20a88a);
|
||||
}
|
||||
.logo.sycamore {
|
||||
color: #0000;
|
||||
font-size: 3rem;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
background-image: linear-gradient(to right,#fdba74, #f87171);
|
||||
font-family: Inter,system-ui,sans-serif;
|
||||
}
|
||||
.logo.sycamore:hover {
|
||||
filter: drop-shadow(0 0 2em #f87171);
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: 0.75s;
|
||||
}
|
||||
|
||||
.logo.tauri:hover {
|
||||
filter: drop-shadow(0 0 2em #24c8db);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
color: #0f0f0f;
|
||||
background-color: #ffffff;
|
||||
transition: border-color 0.25s;
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #396cd8;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#greet-input {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #24c8db;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
color: #ffffff;
|
||||
background-color: #0f0f0f98;
|
||||
}
|
||||
}
|
2
examples/test/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
target
|
||||
dist
|
3894
examples/test/Cargo.lock
generated
Normal file
|
@ -1,21 +1,19 @@
|
|||
[package]
|
||||
name = "tauri-app-ui"
|
||||
name = "tauri-sys-test-ui"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[dependencies]
|
||||
tauri-sys = { path = "../../", features = ["all"] }
|
||||
serde = { version = "1.0.140", features = ["derive"] }
|
||||
sycamore = { git = "https://github.com/sycamore-rs/sycamore", rev = "abd556cbc02047042dad2ebd04405e455a9b11b2", features = ["suspense", "hydrate"] }
|
||||
sycamore-router = { git = "https://github.com/sycamore-rs/sycamore", rev = "abd556cbc02047042dad2ebd04405e455a9b11b2" }
|
||||
log = "0.4.17"
|
||||
sycamore = { git = "https://github.com/sycamore-rs/sycamore", rev = "abd556cbc02047042dad2ebd04405e455a9b11b2", features = ["suspense"] }
|
||||
anyhow = "1.0.66"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
wasm-bindgen-futures = "0.4.32"
|
||||
futures-util = "0.3.25"
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
wasm-logger = "0.2.0"
|
||||
gloo-timers = "0.2.4"
|
||||
shared = { path = "shared" }
|
||||
log = "0.4.17"
|
||||
|
||||
[features]
|
||||
ssg = ["sycamore/ssr"]
|
||||
|
||||
[workspace]
|
||||
members = ["src-tauri", "shared"]
|
||||
ci = []
|
10
examples/test/Trunk.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[build]
|
||||
target = "./index.html"
|
||||
|
||||
[watch]
|
||||
ignore = ["./src-tauri"]
|
||||
|
||||
[serve]
|
||||
address = "127.0.0.1"
|
||||
port = 1420
|
||||
open = false
|
7
examples/test/index.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Tauri + Yew App</title>
|
||||
</head>
|
||||
</html>
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "tauri-app"
|
||||
name = "tauri-sys-test"
|
||||
version = "0.0.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
|
@ -11,13 +11,12 @@ rust-version = "1.57"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { git = "https://github.com/tauri-apps/tauri", features = [] }
|
||||
tauri-build = { version = "1.2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { git = "https://github.com/tauri-apps/tauri", features = ["api-all", "updater"] }
|
||||
shared = { path = "../shared" }
|
||||
tauri = { version = "1.2", features = ["api-all"] }
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
6
examples/test/src-tauri/ci.tauri.conf.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"build": {
|
||||
"beforeDevCommand": "trunk serve --features ci",
|
||||
"beforeBuildCommand": "trunk build --release --features ci"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 974 B After Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 903 B |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
41
examples/test/src-tauri/src/main.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use tauri::{Manager, State, api::notification::Notification};
|
||||
|
||||
struct Received(AtomicBool);
|
||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
||||
#[tauri::command]
|
||||
fn verify_receive(emitted: State<Received>) -> bool {
|
||||
emitted.0.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn exit_with_error(e: &str) -> bool {
|
||||
eprintln!("{}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![verify_receive, exit_with_error])
|
||||
.setup(|app| {
|
||||
app.manage(Received(AtomicBool::new(false)));
|
||||
|
||||
let app_handle = app.handle();
|
||||
app.listen_global("foo", move |_| {
|
||||
app_handle
|
||||
.state::<Received>()
|
||||
.0
|
||||
.store(true, Ordering::Relaxed);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
"withGlobalTauri": true
|
||||
},
|
||||
"package": {
|
||||
"productName": "tauri-app",
|
||||
"productName": "tauri-sys-test",
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"tauri": {
|
||||
|
@ -63,7 +63,7 @@
|
|||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"resizable": true,
|
||||
"title": "tauri-app",
|
||||
"title": "tauri-sys testing suite",
|
||||
"width": 800
|
||||
}
|
||||
]
|
34
examples/test/src/app.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::app;
|
||||
|
||||
pub async fn get_name() -> anyhow::Result<()> {
|
||||
let name = app::get_name().await?;
|
||||
|
||||
ensure!(name == "tauri-sys-test");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_version() -> anyhow::Result<()> {
|
||||
let version = app::get_version().await?;
|
||||
|
||||
ensure!(version.major == 0);
|
||||
ensure!(version.minor == 0);
|
||||
ensure!(version.patch == 0);
|
||||
ensure!(version.build.is_empty());
|
||||
ensure!(version.pre.is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tauri_version() -> anyhow::Result<()> {
|
||||
let version = app::get_tauri_version().await?;
|
||||
|
||||
ensure!(version.major == 1);
|
||||
ensure!(version.minor == 2);
|
||||
ensure!(version.patch == 0);
|
||||
ensure!(version.build.is_empty());
|
||||
ensure!(version.pre.is_empty());
|
||||
|
||||
Ok(())
|
||||
}
|
12
examples/test/src/clipboard.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::clipboard;
|
||||
|
||||
pub async fn test() -> anyhow::Result<()> {
|
||||
clipboard::write_text("foobar").await?;
|
||||
|
||||
let text = clipboard::read_text().await?;
|
||||
|
||||
ensure!(text == "foobar".to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
97
examples/test/src/dialog.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::dialog::{FileDialogBuilder, MessageDialogBuilder, MessageDialogType};
|
||||
|
||||
pub async fn ask() -> anyhow::Result<()> {
|
||||
let mut builder = MessageDialogBuilder::new();
|
||||
builder.set_title("Tauri");
|
||||
builder.set_type(MessageDialogType::Warning);
|
||||
|
||||
let works = builder
|
||||
.ask("Does this work? \n Click Yes to mark this test as passing")
|
||||
.await?;
|
||||
|
||||
ensure!(works);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn confirm() -> anyhow::Result<()> {
|
||||
let mut builder = MessageDialogBuilder::new();
|
||||
builder.set_title("Tauri");
|
||||
builder.set_type(MessageDialogType::Warning);
|
||||
|
||||
let works = builder
|
||||
.confirm("Does this work? \n Click Ok to mark this test as passing")
|
||||
.await?;
|
||||
|
||||
ensure!(works);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn message() -> anyhow::Result<()> {
|
||||
let mut builder = MessageDialogBuilder::new();
|
||||
builder.set_title("Tauri");
|
||||
builder.set_type(MessageDialogType::Warning);
|
||||
|
||||
builder.message("This is a message just for you!").await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pick_file() -> anyhow::Result<()> {
|
||||
let mut builder = FileDialogBuilder::new();
|
||||
builder.set_title("Select a file to mark this test as passing");
|
||||
|
||||
let file = builder.pick_file().await?;
|
||||
|
||||
ensure!(file.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pick_files() -> anyhow::Result<()> {
|
||||
let mut builder = FileDialogBuilder::new();
|
||||
builder.set_title("Select a multiple files to mark this test as passing");
|
||||
|
||||
let file = builder.pick_files().await?;
|
||||
|
||||
ensure!(file.is_some());
|
||||
ensure!(file.unwrap().len() > 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pick_folder() -> anyhow::Result<()> {
|
||||
let mut builder = FileDialogBuilder::new();
|
||||
builder.set_title("Select a folder to mark this test as passing");
|
||||
|
||||
let file = builder.pick_folder().await?;
|
||||
|
||||
ensure!(file.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pick_folders() -> anyhow::Result<()> {
|
||||
let mut builder = FileDialogBuilder::new();
|
||||
builder.set_title("Select a multiple folders to mark this test as passing");
|
||||
|
||||
let file = builder.pick_folders().await?;
|
||||
|
||||
ensure!(file.is_some());
|
||||
ensure!(file.unwrap().len() > 1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn save() -> anyhow::Result<()> {
|
||||
let mut builder = FileDialogBuilder::new();
|
||||
builder.set_title("Select a file to mark this test as passing");
|
||||
|
||||
let file = builder.save().await?;
|
||||
|
||||
ensure!(file.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
10
examples/test/src/event.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::{event, tauri};
|
||||
|
||||
pub async fn emit() -> anyhow::Result<()> {
|
||||
event::emit("foo", &"bar").await?;
|
||||
|
||||
ensure!(tauri::invoke::<_, bool>("verify_receive", &()).await?);
|
||||
|
||||
Ok(())
|
||||
}
|
175
examples/test/src/main.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
mod app;
|
||||
mod clipboard;
|
||||
mod event;
|
||||
mod window;
|
||||
mod dialog;
|
||||
mod notification;
|
||||
mod os;
|
||||
|
||||
extern crate console_error_panic_hook;
|
||||
use std::future::Future;
|
||||
use std::panic;
|
||||
use sycamore::prelude::*;
|
||||
use sycamore::suspense::Suspense;
|
||||
|
||||
#[cfg(feature = "ci")]
|
||||
async fn exit_with_error(e: String) {
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Args {
|
||||
e: String,
|
||||
}
|
||||
|
||||
tauri_sys::tauri::invoke::<_, ()>("exit_with_error", &Args { e })
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct TestProps<'a, F>
|
||||
where
|
||||
F: Future<Output = anyhow::Result<()>> + 'a,
|
||||
{
|
||||
name: &'a str,
|
||||
test: F,
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub async fn Test<'a, G: Html, F>(cx: Scope<'a>, props: TestProps<'a, F>) -> View<G>
|
||||
where
|
||||
F: Future<Output = anyhow::Result<()>> + 'a,
|
||||
{
|
||||
let res = props.test.await;
|
||||
|
||||
view! { cx,
|
||||
tr {
|
||||
td { code { (props.name.to_string()) } }
|
||||
td { (if let Err(e) = &res {
|
||||
#[cfg(feature = "ci")]
|
||||
{
|
||||
wasm_bindgen_futures::spawn_local(exit_with_error(e.to_string()));
|
||||
unreachable!()
|
||||
}
|
||||
#[cfg(not(feature = "ci"))]
|
||||
format!("❌ {:?}", e)
|
||||
} else {
|
||||
format!("✅")
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ci"))]
|
||||
#[component]
|
||||
pub async fn InteractiveTest<'a, G: Html, F>(cx: Scope<'a>, props: TestProps<'a, F>) -> View<G>
|
||||
where
|
||||
F: Future<Output = anyhow::Result<()>> + 'a,
|
||||
{
|
||||
let mut test = Some(props.test);
|
||||
let render_test = create_signal(cx, false);
|
||||
|
||||
let run_test = |_| {
|
||||
render_test.set(true);
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
(if *render_test.get() {
|
||||
let test = test.take().unwrap();
|
||||
|
||||
let fallback = view! { cx,
|
||||
tr {
|
||||
td { code { (props.name.to_string()) } }
|
||||
td {
|
||||
"Running Test..."
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
Suspense(fallback=fallback) {
|
||||
Test(name=props.name, test=test)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
view! { cx,
|
||||
tr {
|
||||
td { code { (props.name.to_string()) } }
|
||||
td {
|
||||
button(on:click=run_test) { "Run Interactive Test"}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ci")]
|
||||
#[component]
|
||||
pub async fn InteractiveTest<'a, G: Html, F>(cx: Scope<'a>, _props: TestProps<'a, F>) -> View<G>
|
||||
where
|
||||
F: Future<Output = anyhow::Result<()>> + 'a,
|
||||
{
|
||||
view! { cx, "Interactive tests are not run in CI mode" }
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub async fn Terminate<'a, G: Html>(cx: Scope<'a>) -> View<G> {
|
||||
#[cfg(feature = "ci")]
|
||||
sycamore::suspense::await_suspense(cx, async {
|
||||
tauri_sys::process::exit(0).await;
|
||||
})
|
||||
.await;
|
||||
|
||||
view! {
|
||||
cx,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::default());
|
||||
|
||||
panic::set_hook(Box::new(|info| {
|
||||
console_error_panic_hook::hook(info);
|
||||
|
||||
#[cfg(feature = "ci")]
|
||||
wasm_bindgen_futures::spawn_local(exit_with_error(format!("{}", info)));
|
||||
}));
|
||||
|
||||
sycamore::render(|cx| {
|
||||
view! { cx,
|
||||
table {
|
||||
tbody {
|
||||
Suspense(fallback=view!{ cx, "Running Tests..." }) {
|
||||
Test(name="app::get_name",test=app::get_name())
|
||||
Test(name="app::get_version",test=app::get_version())
|
||||
Test(name="app::get_tauri_version",test=app::get_tauri_version())
|
||||
Test(name="clipboard::read_text | clipboard::write_text",test=clipboard::test())
|
||||
Test(name="event::emit",test=event::emit())
|
||||
InteractiveTest(name="dialog::message",test=dialog::message())
|
||||
InteractiveTest(name="dialog::ask",test=dialog::ask())
|
||||
InteractiveTest(name="dialog::confirm",test=dialog::confirm())
|
||||
InteractiveTest(name="dialog::pick_file",test=dialog::pick_file())
|
||||
InteractiveTest(name="dialog::pick_files",test=dialog::pick_files())
|
||||
InteractiveTest(name="dialog::pick_folder",test=dialog::pick_folder())
|
||||
InteractiveTest(name="dialog::pick_folders",test=dialog::pick_folders())
|
||||
InteractiveTest(name="dialog::save",test=dialog::save())
|
||||
Test(name="os::arch",test=os::arch())
|
||||
Test(name="os::platform",test=os::platform())
|
||||
Test(name="os::tempdir",test=os::tempdir())
|
||||
Test(name="os::kind",test=os::kind())
|
||||
Test(name="os::version",test=os::version())
|
||||
Test(name="notification::is_permission_granted",test=notification::is_permission_granted())
|
||||
Test(name="notification::request_permission",test=notification::request_permission())
|
||||
InteractiveTest(name="notification::show_notification",test=notification::show_notification())
|
||||
|
||||
// Test(name="window::WebviewWindow::new",test=window::create_window())
|
||||
|
||||
Terminate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
28
examples/test/src/notification.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::notification::{self, Permission};
|
||||
|
||||
pub async fn is_permission_granted() -> anyhow::Result<()> {
|
||||
let granted = notification::is_permission_granted().await?;
|
||||
|
||||
ensure!(granted);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn request_permission() -> anyhow::Result<()> {
|
||||
let permission = notification::request_permission().await?;
|
||||
|
||||
ensure!(permission == Permission::Granted);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn show_notification() -> anyhow::Result<()> {
|
||||
let mut n = notification::Notification::default();
|
||||
n.set_title("TAURI");
|
||||
n.set_body("Tauri is awesome!");
|
||||
|
||||
n.show()?;
|
||||
|
||||
Ok(())
|
||||
}
|
41
examples/test/src/os.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use tauri_sys::os;
|
||||
|
||||
pub async fn arch() -> anyhow::Result<()> {
|
||||
let arch = os::arch().await?;
|
||||
|
||||
log::debug!("{:?}", arch);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn platform() -> anyhow::Result<()> {
|
||||
let platform = os::platform().await?;
|
||||
|
||||
log::debug!("{:?}", platform);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn tempdir() -> anyhow::Result<()> {
|
||||
let tempdir = os::tempdir().await?;
|
||||
|
||||
log::debug!("{:?}", tempdir);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn kind() -> anyhow::Result<()> {
|
||||
let kind = os::kind().await?;
|
||||
|
||||
log::debug!("{:?}", kind);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn version() -> anyhow::Result<()> {
|
||||
let version = os::version().await?;
|
||||
|
||||
log::debug!("{:?}", version);
|
||||
|
||||
Ok(())
|
||||
}
|
13
examples/test/src/window.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use anyhow::ensure;
|
||||
use tauri_sys::window;
|
||||
|
||||
pub async fn create_window() -> anyhow::Result<()> {
|
||||
let win = window::WebviewWindow::new("foo", ());
|
||||
|
||||
ensure!(win.is_visible().await?);
|
||||
// ensure!(win.label() == "foo".to_string());
|
||||
|
||||
win.close().await?;
|
||||
|
||||
Ok(())
|
||||
}
|