Merge remote-tracking branch 'upstream/main' into updater
52
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/workflows/test.yml'
|
||||
- 'src/**'
|
||||
- 'examples/test/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '.github/workflows/test.yml'
|
||||
- 'src/**'
|
||||
- 'examples/test/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install stable toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
target: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: Install native deps
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y webkit2gtk-4.0 at-spi2-core
|
||||
- name: Install Tauri CLI
|
||||
run: |
|
||||
cd examples/test
|
||||
wget -qO- https://github.com/tauri-apps/tauri/releases/download/cli.rs-v1.2.0/cargo-tauri-x86_64-unknown-linux-gnu.tgz | tar -xzf- -C ~/.cargo/bin
|
||||
- name: Install Trunk
|
||||
run: |
|
||||
cd examples/test
|
||||
wget -qO- https://github.com/thedodd/trunk/releases/download/v0.16.0/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- -C ~/.cargo/bin
|
||||
- name: Run test app
|
||||
run: |
|
||||
cd examples/test
|
||||
export CARGO_UNSTABLE_SPARSE_REGISTRY=true
|
||||
xvfb-run cargo tauri dev --exit-on-panic --config ./src-tauri/ci.tauri.conf.json
|
3592
Cargo.lock
generated
20
Cargo.toml
|
@ -11,19 +11,31 @@ js-sys = "0.3.59"
|
|||
serde = { version = "1.0.140", features = ["derive"] }
|
||||
wasm-bindgen = { version = "0.2.82", features = ["serde_json"] }
|
||||
wasm-bindgen-futures = "0.4.32"
|
||||
url = { version = "2.3.1", optional = true }
|
||||
url = { version = "2.3.1", optional = true, features = ["serde"] }
|
||||
thiserror = "1.0.37"
|
||||
semver = { version = "1.0.14", optional = true }
|
||||
semver = { version = "1.0.14", optional = true, features = ["serde"] }
|
||||
log = "0.4.17"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.33"
|
||||
tauri-sys = { path = ".", features = ["all"] }
|
||||
# tauri = "1.1.1"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[features]
|
||||
all = ["app", "clipboard", "event", "mocks", "tauri", "updater"]
|
||||
all = ["app", "clipboard", "event", "mocks", "tauri", "window", "process", "dialog", "os", "notification"]
|
||||
app = ["dep:semver"]
|
||||
clipboard = []
|
||||
dialog = []
|
||||
event = []
|
||||
mocks = []
|
||||
tauri = ["dep:url"]
|
||||
updater = []
|
||||
window = []
|
||||
process = []
|
||||
os = ["dep:semver"]
|
||||
notification = []
|
||||
|
||||
[workspace]
|
||||
members = ["examples/test", "examples/test/src-tauri"]
|
||||
|
|
11
README.md
|
@ -43,6 +43,7 @@ All modules are gated by accordingly named Cargo features. It is recommended you
|
|||
- **all**: Enables all modules.
|
||||
- **app**: Enables the `app` module.
|
||||
- **clipboard**: Enables the `clipboard` module.
|
||||
- **dialog**: Enables the `dialog` module.
|
||||
- **event**: Enables the `event` module.
|
||||
- **mocks**: Enables the `mocks` module.
|
||||
- **tauri**: Enables the `tauri` module.
|
||||
|
@ -54,20 +55,20 @@ These API bindings are not completely on-par with `@tauri-apps/api` yet, but her
|
|||
- [x] `app`
|
||||
- [ ] `cli`
|
||||
- [x] `clipboard`
|
||||
- [ ] `dialog`
|
||||
- [x] `dialog`
|
||||
- [x] `event`
|
||||
- [ ] `fs`
|
||||
- [ ] `global_shortcut`
|
||||
- [ ] `http`
|
||||
- [x] `mocks`
|
||||
- [ ] `notification`
|
||||
- [ ] `os`
|
||||
- [x] `notification`
|
||||
- [x] `os`
|
||||
- [ ] `path`
|
||||
- [ ] `process`
|
||||
- [x] `process`
|
||||
- [ ] `shell`
|
||||
- [x] `tauri`
|
||||
- [ ] `updater`
|
||||
- [ ] `window`
|
||||
- [x] `window`
|
||||
|
||||
The current API also very closely mirrors the JS API even though that might not be the most ergonomic choice, ideas for improving the API with quality-of-life features beyond the regular JS API interface are very welcome.
|
||||
|
||||
|
|
32
build.rs
|
@ -1,32 +0,0 @@
|
|||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
/* Shared arguments */
|
||||
let sargs: [&str; 9] = [
|
||||
"--outdir=dist",
|
||||
"--format=esm",
|
||||
"--bundle",
|
||||
"tauri/tooling/api/src/app.ts",
|
||||
"tauri/tooling/api/src/clipboard.ts",
|
||||
"tauri/tooling/api/src/tauri.ts",
|
||||
"tauri/tooling/api/src/event.ts",
|
||||
"tauri/tooling/api/src/mocks.ts",
|
||||
"tauri/tooling/api/src/updater.ts",
|
||||
];
|
||||
|
||||
if cfg!(windows) {
|
||||
/* Use cmd if the target is windows */
|
||||
Command::new("cmd")
|
||||
.args(&["/C", "esbuild"])
|
||||
.args(&sargs)
|
||||
.output()
|
||||
.unwrap();
|
||||
} else if cfg!(unix) {
|
||||
Command::new("esbuild")
|
||||
.args(&sargs)
|
||||
.output()
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("Unsupported build target");
|
||||
}
|
||||
}
|
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(())
|
||||
}
|
15
package.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "tauri-sys",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "esbuild --outdir=src --format=esm --bundle tauri/tooling/api/src/*.ts"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.15.13"
|
||||
}
|
||||
}
|
237
pnpm-lock.yaml
generated
Normal file
|
@ -0,0 +1,237 @@
|
|||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
esbuild: ^0.15.13
|
||||
|
||||
devDependencies:
|
||||
esbuild: 0.15.13
|
||||
|
||||
packages:
|
||||
|
||||
/@esbuild/android-arm/0.15.13:
|
||||
resolution: {integrity: sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64/0.15.13:
|
||||
resolution: {integrity: sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-android-64/0.15.13:
|
||||
resolution: {integrity: sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-android-arm64/0.15.13:
|
||||
resolution: {integrity: sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-darwin-64/0.15.13:
|
||||
resolution: {integrity: sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-darwin-arm64/0.15.13:
|
||||
resolution: {integrity: sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-freebsd-64/0.15.13:
|
||||
resolution: {integrity: sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-freebsd-arm64/0.15.13:
|
||||
resolution: {integrity: sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-32/0.15.13:
|
||||
resolution: {integrity: sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-64/0.15.13:
|
||||
resolution: {integrity: sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-arm/0.15.13:
|
||||
resolution: {integrity: sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-arm64/0.15.13:
|
||||
resolution: {integrity: sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-mips64le/0.15.13:
|
||||
resolution: {integrity: sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-ppc64le/0.15.13:
|
||||
resolution: {integrity: sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-riscv64/0.15.13:
|
||||
resolution: {integrity: sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-s390x/0.15.13:
|
||||
resolution: {integrity: sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-netbsd-64/0.15.13:
|
||||
resolution: {integrity: sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-openbsd-64/0.15.13:
|
||||
resolution: {integrity: sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-sunos-64/0.15.13:
|
||||
resolution: {integrity: sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-32/0.15.13:
|
||||
resolution: {integrity: sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-64/0.15.13:
|
||||
resolution: {integrity: sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-arm64/0.15.13:
|
||||
resolution: {integrity: sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/esbuild/0.15.13:
|
||||
resolution: {integrity: sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@esbuild/android-arm': 0.15.13
|
||||
'@esbuild/linux-loong64': 0.15.13
|
||||
esbuild-android-64: 0.15.13
|
||||
esbuild-android-arm64: 0.15.13
|
||||
esbuild-darwin-64: 0.15.13
|
||||
esbuild-darwin-arm64: 0.15.13
|
||||
esbuild-freebsd-64: 0.15.13
|
||||
esbuild-freebsd-arm64: 0.15.13
|
||||
esbuild-linux-32: 0.15.13
|
||||
esbuild-linux-64: 0.15.13
|
||||
esbuild-linux-arm: 0.15.13
|
||||
esbuild-linux-arm64: 0.15.13
|
||||
esbuild-linux-mips64le: 0.15.13
|
||||
esbuild-linux-ppc64le: 0.15.13
|
||||
esbuild-linux-riscv64: 0.15.13
|
||||
esbuild-linux-s390x: 0.15.13
|
||||
esbuild-netbsd-64: 0.15.13
|
||||
esbuild-openbsd-64: 0.15.13
|
||||
esbuild-sunos-64: 0.15.13
|
||||
esbuild-windows-32: 0.15.13
|
||||
esbuild-windows-64: 0.15.13
|
||||
esbuild-windows-arm64: 0.15.13
|
||||
dev: true
|
43
src/app.rs
|
@ -9,8 +9,10 @@ use semver::Version;
|
|||
/// const appName = await getName();
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn get_name() -> String {
|
||||
inner::getName().await.as_string().unwrap()
|
||||
pub async fn get_name() -> crate::Result<String> {
|
||||
let js_val = inner::getName().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
/// Gets the application version.
|
||||
|
@ -23,8 +25,10 @@ pub async fn get_name() -> String {
|
|||
/// let version = get_version().await;
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn get_version() -> Version {
|
||||
Version::parse(&inner::getVersion().await.as_string().unwrap()).unwrap()
|
||||
pub async fn get_version() -> crate::Result<Version> {
|
||||
let js_val = inner::getVersion().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
/// Gets the Tauri version.
|
||||
|
@ -37,8 +41,10 @@ pub async fn get_version() -> Version {
|
|||
/// let version = get_tauri_version().await;
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn get_tauri_version() -> Version {
|
||||
Version::parse(&inner::getTauriVersion().await.as_string().unwrap()).unwrap()
|
||||
pub async fn get_tauri_version() -> crate::Result<Version> {
|
||||
let js_val = inner::getTauriVersion().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
/// Shows the application on macOS. This function does not automatically focuses any app window.
|
||||
|
@ -51,8 +57,8 @@ pub async fn get_tauri_version() -> Version {
|
|||
/// show().await;
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn show() {
|
||||
inner::show().await;
|
||||
pub async fn show() -> crate::Result<()> {
|
||||
Ok(inner::show().await?)
|
||||
}
|
||||
|
||||
/// Hides the application on macOS.
|
||||
|
@ -65,19 +71,24 @@ pub async fn show() {
|
|||
/// hide().await;
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn hide() {
|
||||
inner::hide().await;
|
||||
pub async fn hide() -> crate::Result<()> {
|
||||
Ok(inner::hide().await?)
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
#[wasm_bindgen(module = "/dist/app.js")]
|
||||
#[wasm_bindgen(module = "/src/app.js")]
|
||||
extern "C" {
|
||||
pub async fn getName() -> JsValue;
|
||||
pub async fn getTauriVersion() -> JsValue;
|
||||
pub async fn getVersion() -> JsValue;
|
||||
pub async fn hide();
|
||||
pub async fn show();
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn getName() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn getTauriVersion() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn getVersion() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn hide() -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn show() -> Result<(), JsValue>;
|
||||
}
|
||||
}
|
||||
|
|
55
src/cli.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/cli.ts
|
||||
async function getMatches() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Cli",
|
||||
message: {
|
||||
cmd: "cliMatches"
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
getMatches
|
||||
};
|
|
@ -8,8 +8,10 @@
|
|||
/// let clipboard_text = read_text().await;
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn read_text() -> Option<String> {
|
||||
inner::readText().await.as_string()
|
||||
pub async fn read_text() -> crate::Result<String> {
|
||||
let js_val = inner::readText().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
/// Writes plain text to the clipboard.
|
||||
|
@ -25,16 +27,18 @@ pub async fn read_text() -> Option<String> {
|
|||
///
|
||||
/// @returns A promise indicating the success or failure of the operation.
|
||||
#[inline(always)]
|
||||
pub async fn write_text(text: &str) {
|
||||
inner::writeText(text).await
|
||||
pub async fn write_text(text: &str) -> crate::Result<()> {
|
||||
Ok(inner::writeText(text).await?)
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
#[wasm_bindgen(module = "/dist/clipboard.js")]
|
||||
#[wasm_bindgen(module = "/src/clipboard.js")]
|
||||
extern "C" {
|
||||
pub async fn readText() -> JsValue;
|
||||
pub async fn writeText(text: &str);
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn readText() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn writeText(text: &str) -> Result<(), JsValue>;
|
||||
}
|
||||
}
|
||||
|
|
111
src/dialog.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/dialog.ts
|
||||
async function open(options = {}) {
|
||||
if (typeof options === "object") {
|
||||
Object.freeze(options);
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Dialog",
|
||||
message: {
|
||||
cmd: "openDialog",
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function save(options = {}) {
|
||||
if (typeof options === "object") {
|
||||
Object.freeze(options);
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Dialog",
|
||||
message: {
|
||||
cmd: "saveDialog",
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function message(message2, options) {
|
||||
const opts = typeof options === "string" ? { title: options } : options;
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Dialog",
|
||||
message: {
|
||||
cmd: "messageDialog",
|
||||
message: message2.toString(),
|
||||
title: opts?.title?.toString(),
|
||||
type: opts?.type
|
||||
}
|
||||
});
|
||||
}
|
||||
async function ask(message2, options) {
|
||||
const opts = typeof options === "string" ? { title: options } : options;
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Dialog",
|
||||
message: {
|
||||
cmd: "askDialog",
|
||||
message: message2.toString(),
|
||||
title: opts?.title?.toString(),
|
||||
type: opts?.type
|
||||
}
|
||||
});
|
||||
}
|
||||
async function confirm(message2, options) {
|
||||
const opts = typeof options === "string" ? { title: options } : options;
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Dialog",
|
||||
message: {
|
||||
cmd: "confirmDialog",
|
||||
message: message2.toString(),
|
||||
title: opts?.title?.toString(),
|
||||
type: opts?.type
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
ask,
|
||||
confirm,
|
||||
message,
|
||||
open,
|
||||
save
|
||||
};
|
604
src/dialog.rs
Normal file
|
@ -0,0 +1,604 @@
|
|||
use serde::Serialize;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct DialogFilter<'a> {
|
||||
extensions: &'a [&'a str],
|
||||
name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
#[serde(rename = "camelCase")]
|
||||
pub struct FileDialogBuilder<'a> {
|
||||
default_path: Option<&'a Path>,
|
||||
filters: Vec<DialogFilter<'a>>,
|
||||
title: Option<&'a str>,
|
||||
directory: bool,
|
||||
multiple: bool,
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
impl<'a> FileDialogBuilder<'a> {
|
||||
/// Gets the default file dialog builder.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set starting file name or directory of the dialog.
|
||||
pub fn set_default_path(&mut self, default_path: &'a Path) {
|
||||
self.default_path = Some(default_path);
|
||||
}
|
||||
|
||||
/// If directory is true, indicates that it will be read recursively later.
|
||||
/// Defines whether subdirectories will be allowed on the scope or not.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = FileDialogBuilder::new().set_recursive(true);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn set_recursive(&mut self, recursive: bool) {
|
||||
self.recursive = recursive;
|
||||
}
|
||||
|
||||
/// Set the title of the dialog.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = FileDialogBuilder::new().set_title("Test Title");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn set_title(&mut self, title: &'a str) {
|
||||
self.title = Some(title);
|
||||
}
|
||||
|
||||
/// Add file extension filter. Takes in the name of the filter, and list of extensions
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = FileDialogBuilder::new().add_filter("Image", &["png", "jpeg"]);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn add_filter(&mut self, name: &'a str, extensions: &'a [&'a str]) {
|
||||
self.filters.push(DialogFilter { name, extensions });
|
||||
}
|
||||
|
||||
/// Add many file extension filters.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = FileDialogBuilder::new().add_filters(&[("Image", &["png", "jpeg"]),("Video", &["mp4"])]);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn add_filters(&mut self, filters: impl IntoIterator<Item = (&'a str, &'a [&'a str])>) {
|
||||
for (name, extensions) in filters.into_iter() {
|
||||
self.filters.push(DialogFilter {
|
||||
name: name.as_ref(),
|
||||
extensions,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the dialog to select a single file.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let file = FileDialogBuilder::new().pick_file().await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn pick_file(self) -> crate::Result<Option<PathBuf>> {
|
||||
let raw = inner::open(serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
/// Shows the dialog to select multiple files.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let files = FileDialogBuilder::new().pick_files().await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn pick_files(mut self) -> crate::Result<Option<Vec<PathBuf>>> {
|
||||
self.multiple = true;
|
||||
|
||||
let raw = inner::open(serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
/// Shows the dialog to select a single folder.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let files = FileDialogBuilder::new().pick_folder().await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn pick_folder(mut self) -> crate::Result<Option<PathBuf>> {
|
||||
self.directory = true;
|
||||
|
||||
let raw = inner::open(serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
/// Shows the dialog to select multiple folders.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let files = FileDialogBuilder::new().pick_folders().await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn pick_folders(mut self) -> crate::Result<Option<Vec<PathBuf>>> {
|
||||
self.directory = true;
|
||||
self.multiple = true;
|
||||
|
||||
let raw = inner::open(serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
/// Open a file/directory save dialog.
|
||||
///
|
||||
/// The selected path is added to the filesystem and asset protocol allowlist scopes.
|
||||
/// When security is more important than the easy of use of this API, prefer writing a dedicated command instead.
|
||||
///
|
||||
/// Note that the allowlist scope change is not persisted, so the values are cleared when the application is restarted.
|
||||
/// You can save it to the filesystem using tauri-plugin-persisted-scope.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::FileDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let file = FileDialogBuilder::new().save().await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn save(self) -> crate::Result<Option<PathBuf>> {
|
||||
let raw = inner::save(serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum MessageDialogType {
|
||||
#[default]
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl Serialize for MessageDialogType {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match self {
|
||||
MessageDialogType::Info => serializer.serialize_str("info"),
|
||||
MessageDialogType::Warning => serializer.serialize_str("warning"),
|
||||
MessageDialogType::Error => serializer.serialize_str("error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub struct MessageDialogBuilder<'a> {
|
||||
title: Option<&'a str>,
|
||||
r#type: MessageDialogType,
|
||||
}
|
||||
|
||||
impl<'a> MessageDialogBuilder<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set the title of the dialog.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::MessageDialogBuilder;
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = MessageDialogBuilder::new().set_title("Test Title");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn set_title(&mut self, title: &'a str) {
|
||||
self.title = Some(title);
|
||||
}
|
||||
|
||||
/// Set the type of the dialog.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri_sys::dialog::{MessageDialogBuilder,MessageDialogType};
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let _builder = MessageDialogBuilder::new().set_type(MessageDialogType::Error);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn set_type(&mut self, r#type: MessageDialogType) {
|
||||
self.r#type = r#type;
|
||||
}
|
||||
|
||||
/// Shows a message dialog with an `Ok` button.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::MessageDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let file = MessageDialogBuilder::new().message("Tauri is awesome").await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn message(self, message: &str) -> crate::Result<()> {
|
||||
Ok(inner::message(message, serde_wasm_bindgen::to_value(&self)?).await?)
|
||||
}
|
||||
|
||||
/// Shows a question dialog with `Yes` and `No` buttons.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::MessageDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let confirmation = MessageDialogBuilder::new().ask("Are you sure?").await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn ask(self, message: &str) -> crate::Result<bool> {
|
||||
let raw = inner::ask(message, serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
/// Shows a question dialog with `Ok` and `Cancel` buttons.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use tauri_sys::dialog::MessageDialogBuilder;
|
||||
///
|
||||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let confirmation = MessageDialogBuilder::new().confirm("Are you sure?").await?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn confirm(self, message: &str) -> crate::Result<bool> {
|
||||
let raw = inner::confirm(message, serde_wasm_bindgen::to_value(&self)?).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
}
|
||||
|
||||
// //! User interaction with the file system using dialog boxes.
|
||||
// //!
|
||||
// //! # Example
|
||||
// //!
|
||||
// //! ```rust,no_run
|
||||
// //! use tauri_api::dialog::open;
|
||||
// //!
|
||||
// //! let path = open(None).await;
|
||||
// //! ```
|
||||
// use serde::Serialize;
|
||||
// use std::path::PathBuf;
|
||||
|
||||
// /// Extension filter for the file dialog.
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// let filter = DialogFilter {
|
||||
// /// extension: vec![".jpg", ".jpeg", ".png", ".bmp"],
|
||||
// /// name: "images",
|
||||
// /// };
|
||||
// /// ```
|
||||
// #[derive(Serialize)]
|
||||
// pub struct DialogFilter {
|
||||
// /// Extensions to filter, without a `.` prefix.
|
||||
// pub extensions: Vec<String>,
|
||||
|
||||
// /// Filter name
|
||||
// pub name: String,
|
||||
// }
|
||||
|
||||
// /// Types of a [`message`] dialog.
|
||||
// #[derive(Serialize)]
|
||||
// pub enum MessageDialogType {
|
||||
// Error,
|
||||
// Info,
|
||||
// Warning,
|
||||
// }
|
||||
|
||||
// /// Options for the [`message`] dialog.
|
||||
// #[derive(Serialize)]
|
||||
// pub struct MessageDialogOptions {
|
||||
// /// The title of the dialog. Defaults to the app name.
|
||||
// pub title: Option<String>,
|
||||
|
||||
// /// The type of the dialog. Defaults to MessageDialogType::Info.
|
||||
// #[serde(rename(serialize = "type"))]
|
||||
// pub kind: MessageDialogType,
|
||||
// }
|
||||
|
||||
// impl MessageDialogOptions {
|
||||
// /// Creates a new `MessageDialogOptions` with sensible default values.
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// title: None,
|
||||
// kind: MessageDialogType::Info,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Options for an [`open`] dialog.
|
||||
// #[derive(Serialize)]
|
||||
// pub struct OpenDialogOptions {
|
||||
// /// Initial directory or file path.
|
||||
// #[serde(rename(serialize = "defaultPath"))]
|
||||
// pub default_path: Option<PathBuf>,
|
||||
|
||||
// /// Whether the dialog is a directory selection or not.
|
||||
// pub directory: bool,
|
||||
|
||||
// /// The filters of the dialog.
|
||||
// pub filters: Vec<DialogFilter>,
|
||||
|
||||
// /// Whether the dialog allows multiple selection or not.
|
||||
// pub multiple: bool,
|
||||
|
||||
// /// If `directory` is `true`, indicatees that it will be read recursivley later.
|
||||
// /// Defines whether subdirectories will be allowed on the scope or not.
|
||||
// pub recursive: bool,
|
||||
|
||||
// /// The title of the dialog window.
|
||||
// pub title: Option<String>,
|
||||
// }
|
||||
|
||||
// impl OpenDialogOptions {
|
||||
// /// Creates a new `OpenDialogOptions` with sensible default values.
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// default_path: None,
|
||||
// directory: false,
|
||||
// filters: Vec::new(),
|
||||
// multiple: false,
|
||||
// recursive: false,
|
||||
// title: None,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Options for the save dialog.
|
||||
// #[derive(Serialize)]
|
||||
// pub struct SaveDialogOptions {
|
||||
// /// Initial directory of the file path.
|
||||
// /// If it's not a directory path, the dialog interface will change to that folder.
|
||||
// /// If it's not an existing directory, the file name will be set to the dialog's
|
||||
// /// file name input and the dialog will be set to the parent folder.
|
||||
// #[serde(rename(serialize = "defaultPath"))]
|
||||
// pub default_path: Option<PathBuf>,
|
||||
|
||||
// /// The filters of the dialog.
|
||||
// pub filters: Vec<DialogFilter>,
|
||||
|
||||
// /// The title of the dialog window.
|
||||
// pub title: Option<String>,
|
||||
// }
|
||||
|
||||
// impl SaveDialogOptions {
|
||||
// /// Creates a new `SaveDialogOptions` with sensible default values.
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// default_path: None,
|
||||
// filters: Vec::new(),
|
||||
// title: None,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Show a question dialog with `Yes` and `No` buttons.
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{ask, MessageDialogOptions};
|
||||
// ///
|
||||
// /// let yes = ask("Are you sure?", None).await;
|
||||
// /// ```
|
||||
// /// @param message Message to display.
|
||||
// /// @param options Dialog options.
|
||||
// /// @returns Whether the user selected `Yes` or `No`.
|
||||
// #[inline(always)]
|
||||
// pub async fn ask(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<bool> {
|
||||
// let js_val = inner::ask(message, serde_wasm_bindgen::to_value(&options)?).await?;
|
||||
|
||||
// Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
// }
|
||||
|
||||
// /// Shows a question dialog with `Ok` and `Cancel` buttons.
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{confirm, MessageDialogOptions};
|
||||
// ///
|
||||
// /// let confirmed = confirm("Are you sure?", None).await;
|
||||
// /// ```
|
||||
// /// @returns Whether the user selelced `Ok` or `Cancel`.
|
||||
// pub async fn confirm(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<bool> {
|
||||
// let js_val = inner::confirm(message, serde_wasm_bindgen::to_value(&options)?).await?;
|
||||
|
||||
// Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
// }
|
||||
|
||||
// /// Shows a message dialog with an `Ok` button.
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{message, MessageDialogOptions};
|
||||
// ///
|
||||
// /// message("Tauri is awesome", None).await;
|
||||
// /// ```
|
||||
// /// @param message Message to display.
|
||||
// /// @param options Dialog options.
|
||||
// /// @returns Promise resolved when user closes the dialog.
|
||||
// pub async fn message(message: &str, options: Option<MessageDialogOptions>) -> crate::Result<()> {
|
||||
// Ok(inner::message(message, serde_wasm_bindgen::to_value(&options)?).await?)
|
||||
// }
|
||||
|
||||
// /// Opens a file/directory selection dialog for a single file.
|
||||
// /// `multiple` field of [`options`](OpenDialogOptions) must be `false`, if provided.
|
||||
// ///
|
||||
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
|
||||
// /// When security is mroe important than the ease of use of this API,
|
||||
// /// prefer writing a dedicated command instead.
|
||||
// ///
|
||||
// /// Note that the allowlist scope change is not persisited,
|
||||
// /// so the values are cleared when the applicaiton is restarted.
|
||||
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{open, OpenDialogOptions};
|
||||
// ///
|
||||
// /// let file = open(None).await;
|
||||
// ///
|
||||
// /// let mut opts = OpenDialogOptions::new();
|
||||
// /// opts.directory = true;
|
||||
// /// let dir = open(Some(opts)).await;
|
||||
// /// ```
|
||||
// /// @param options Dialog options.
|
||||
// /// @returns List of file paths, or `None` if user cancelled the dialog.
|
||||
// pub async fn open(options: Option<OpenDialogOptions>) -> crate::Result<Option<PathBuf>> {
|
||||
// let file = inner::open(serde_wasm_bindgen::to_value(&options)?).await?;
|
||||
|
||||
// Ok(serde_wasm_bindgen::from_value(file)?)
|
||||
// }
|
||||
|
||||
// /// Opens a file/directory selection dialog for multiple files.
|
||||
// /// `multiple` field of [`options`](OpenDialogOptions) must be `true`, if provided.
|
||||
// ///
|
||||
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
|
||||
// /// When security is mroe important than the ease of use of this API,
|
||||
// /// prefer writing a dedicated command instead.
|
||||
// ///
|
||||
// /// Note that the allowlist scope change is not persisited,
|
||||
// /// so the values are cleared when the applicaiton is restarted.
|
||||
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{open, OpenDialogOptions};
|
||||
// ///
|
||||
// /// let files = open_multiple(None).await;
|
||||
// ///
|
||||
// /// let mut opts = OpenDialogOptions::new();
|
||||
// /// opts.multiple = true;
|
||||
// /// opts.directory = true;
|
||||
// /// let dirs = open(Some(opts)).await;
|
||||
// /// ```
|
||||
// /// @param options Dialog options.
|
||||
// /// @returns List of file paths, or `None` if user cancelled the dialog.
|
||||
// pub async fn open_multiple(
|
||||
// options: Option<OpenDialogOptions>,
|
||||
// ) -> crate::Result<Option<Vec<PathBuf>>> {
|
||||
// let files = inner::open_multiple(serde_wasm_bindgen::to_value(&options)?).await?;
|
||||
|
||||
// Ok(serde_wasm_bindgen::from_value(files)?)
|
||||
// }
|
||||
|
||||
// /// Opens a file/directory save dialog.
|
||||
// ///
|
||||
// /// The selected paths are added to the filesystem and asset protocol allowlist scopes.
|
||||
// /// When security is mroe important than the ease of use of this API,
|
||||
// /// prefer writing a dedicated command instead.
|
||||
// ///
|
||||
// /// Note that the allowlist scope change is not persisited,
|
||||
// /// so the values are cleared when the applicaiton is restarted.
|
||||
// /// You can save it to the filessytem using the [tauri-plugin-persisted-scope](https://github.com/tauri-apps/tauri-plugin-persisted-scope).
|
||||
// ///
|
||||
// /// # Example
|
||||
// ///
|
||||
// /// ```rust,no_run
|
||||
// /// use tauri_api::dialog::{save, SaveDialogOptions};
|
||||
// ///
|
||||
// /// let file = save(None).await;
|
||||
// /// ```
|
||||
// /// @param options Dialog options.
|
||||
// /// @returns File path, or `None` if user cancelled the dialog.
|
||||
// pub async fn save(options: Option<SaveDialogOptions>) -> crate::Result<Option<PathBuf>> {
|
||||
// let path = inner::save(serde_wasm_bindgen::to_value(&options)?).await?;
|
||||
|
||||
// Ok(serde_wasm_bindgen::from_value(path)?)
|
||||
// }
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
#[wasm_bindgen(module = "/src/dialog.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn ask(message: &str, options: JsValue) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn confirm(message: &str, options: JsValue) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn open(options: JsValue) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn message(message: &str, option: JsValue) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn save(options: JsValue) -> Result<JsValue, JsValue>;
|
||||
}
|
||||
}
|
42
src/event.rs
|
@ -1,6 +1,5 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use wasm_bindgen::{prelude::Closure, JsValue};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -45,8 +44,10 @@ impl<T: Debug> Debug for Event<T> {
|
|||
///
|
||||
/// @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
|
||||
#[inline(always)]
|
||||
pub async fn emit<T: Serialize>(event: &str, payload: &T) {
|
||||
inner::emit(event, serde_wasm_bindgen::to_value(payload).unwrap()).await
|
||||
pub async fn emit<T: Serialize>(event: &str, payload: &T) -> crate::Result<()> {
|
||||
inner::emit(event, serde_wasm_bindgen::to_value(payload)?).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Listen to an event from the backend.
|
||||
|
@ -70,7 +71,7 @@ pub async fn emit<T: Serialize>(event: &str, payload: &T) {
|
|||
///
|
||||
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
|
||||
#[inline(always)]
|
||||
pub async fn listen<T, H>(event: &str, mut handler: H) -> impl FnOnce()
|
||||
pub async fn listen<T, H>(event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
H: FnMut(Event<T>) + 'static,
|
||||
|
@ -79,14 +80,14 @@ where
|
|||
(handler)(serde_wasm_bindgen::from_value(raw).unwrap())
|
||||
});
|
||||
|
||||
let unlisten = inner::listen(event, &closure).await;
|
||||
let unlisten = inner::listen(event, &closure).await?;
|
||||
|
||||
closure.forget();
|
||||
|
||||
let unlisten = js_sys::Function::from(unlisten);
|
||||
move || {
|
||||
Ok(move || {
|
||||
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Listen to an one-off event from the backend.
|
||||
|
@ -115,7 +116,7 @@ where
|
|||
///
|
||||
/// Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
|
||||
#[inline(always)]
|
||||
pub async fn once<T, H>(event: &str, mut handler: H) -> impl FnOnce()
|
||||
pub async fn once<T, H>(event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
H: FnMut(Event<T>) + 'static,
|
||||
|
@ -124,14 +125,14 @@ where
|
|||
(handler)(serde_wasm_bindgen::from_value(raw).unwrap())
|
||||
});
|
||||
|
||||
let unlisten = inner::once(event, &closure).await;
|
||||
let unlisten = inner::once(event, &closure).await?;
|
||||
|
||||
closure.forget();
|
||||
|
||||
let unlisten = js_sys::Function::from(unlisten);
|
||||
move || {
|
||||
Ok(move || {
|
||||
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mod inner {
|
||||
|
@ -140,10 +141,19 @@ mod inner {
|
|||
JsValue,
|
||||
};
|
||||
|
||||
#[wasm_bindgen(module = "/dist/event.js")]
|
||||
#[wasm_bindgen(module = "/src/event.js")]
|
||||
extern "C" {
|
||||
pub async fn emit(event: &str, payload: JsValue);
|
||||
pub async fn listen(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue;
|
||||
pub async fn once(event: &str, handler: &Closure<dyn FnMut(JsValue)>) -> JsValue;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn emit(event: &str, payload: JsValue) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn listen(
|
||||
event: &str,
|
||||
handler: &Closure<dyn FnMut(JsValue)>,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn once(
|
||||
event: &str,
|
||||
handler: &Closure<dyn FnMut(JsValue)>,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
}
|
||||
}
|
||||
|
|
243
src/fs.js
Normal file
|
@ -0,0 +1,243 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/fs.ts
|
||||
var BaseDirectory = /* @__PURE__ */ ((BaseDirectory2) => {
|
||||
BaseDirectory2[BaseDirectory2["Audio"] = 1] = "Audio";
|
||||
BaseDirectory2[BaseDirectory2["Cache"] = 2] = "Cache";
|
||||
BaseDirectory2[BaseDirectory2["Config"] = 3] = "Config";
|
||||
BaseDirectory2[BaseDirectory2["Data"] = 4] = "Data";
|
||||
BaseDirectory2[BaseDirectory2["LocalData"] = 5] = "LocalData";
|
||||
BaseDirectory2[BaseDirectory2["Desktop"] = 6] = "Desktop";
|
||||
BaseDirectory2[BaseDirectory2["Document"] = 7] = "Document";
|
||||
BaseDirectory2[BaseDirectory2["Download"] = 8] = "Download";
|
||||
BaseDirectory2[BaseDirectory2["Executable"] = 9] = "Executable";
|
||||
BaseDirectory2[BaseDirectory2["Font"] = 10] = "Font";
|
||||
BaseDirectory2[BaseDirectory2["Home"] = 11] = "Home";
|
||||
BaseDirectory2[BaseDirectory2["Picture"] = 12] = "Picture";
|
||||
BaseDirectory2[BaseDirectory2["Public"] = 13] = "Public";
|
||||
BaseDirectory2[BaseDirectory2["Runtime"] = 14] = "Runtime";
|
||||
BaseDirectory2[BaseDirectory2["Template"] = 15] = "Template";
|
||||
BaseDirectory2[BaseDirectory2["Video"] = 16] = "Video";
|
||||
BaseDirectory2[BaseDirectory2["Resource"] = 17] = "Resource";
|
||||
BaseDirectory2[BaseDirectory2["App"] = 18] = "App";
|
||||
BaseDirectory2[BaseDirectory2["Log"] = 19] = "Log";
|
||||
BaseDirectory2[BaseDirectory2["Temp"] = 20] = "Temp";
|
||||
BaseDirectory2[BaseDirectory2["AppConfig"] = 21] = "AppConfig";
|
||||
BaseDirectory2[BaseDirectory2["AppData"] = 22] = "AppData";
|
||||
BaseDirectory2[BaseDirectory2["AppLocalData"] = 23] = "AppLocalData";
|
||||
BaseDirectory2[BaseDirectory2["AppCache"] = 24] = "AppCache";
|
||||
BaseDirectory2[BaseDirectory2["AppLog"] = 25] = "AppLog";
|
||||
return BaseDirectory2;
|
||||
})(BaseDirectory || {});
|
||||
async function readTextFile(filePath, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "readTextFile",
|
||||
path: filePath,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function readBinaryFile(filePath, options = {}) {
|
||||
const arr = await invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "readFile",
|
||||
path: filePath,
|
||||
options
|
||||
}
|
||||
});
|
||||
return Uint8Array.from(arr);
|
||||
}
|
||||
async function writeTextFile(path, contents, options) {
|
||||
if (typeof options === "object") {
|
||||
Object.freeze(options);
|
||||
}
|
||||
if (typeof path === "object") {
|
||||
Object.freeze(path);
|
||||
}
|
||||
const file = { path: "", contents: "" };
|
||||
let fileOptions = options;
|
||||
if (typeof path === "string") {
|
||||
file.path = path;
|
||||
} else {
|
||||
file.path = path.path;
|
||||
file.contents = path.contents;
|
||||
}
|
||||
if (typeof contents === "string") {
|
||||
file.contents = contents ?? "";
|
||||
} else {
|
||||
fileOptions = contents;
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "writeFile",
|
||||
path: file.path,
|
||||
contents: Array.from(new TextEncoder().encode(file.contents)),
|
||||
options: fileOptions
|
||||
}
|
||||
});
|
||||
}
|
||||
async function writeBinaryFile(path, contents, options) {
|
||||
if (typeof options === "object") {
|
||||
Object.freeze(options);
|
||||
}
|
||||
if (typeof path === "object") {
|
||||
Object.freeze(path);
|
||||
}
|
||||
const file = { path: "", contents: [] };
|
||||
let fileOptions = options;
|
||||
if (typeof path === "string") {
|
||||
file.path = path;
|
||||
} else {
|
||||
file.path = path.path;
|
||||
file.contents = path.contents;
|
||||
}
|
||||
if (contents && "dir" in contents) {
|
||||
fileOptions = contents;
|
||||
} else if (typeof path === "string") {
|
||||
file.contents = contents ?? [];
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "writeFile",
|
||||
path: file.path,
|
||||
contents: Array.from(
|
||||
file.contents instanceof ArrayBuffer ? new Uint8Array(file.contents) : file.contents
|
||||
),
|
||||
options: fileOptions
|
||||
}
|
||||
});
|
||||
}
|
||||
async function readDir(dir, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "readDir",
|
||||
path: dir,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function createDir(dir, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "createDir",
|
||||
path: dir,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function removeDir(dir, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "removeDir",
|
||||
path: dir,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function copyFile(source, destination, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "copyFile",
|
||||
source,
|
||||
destination,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function removeFile(file, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "removeFile",
|
||||
path: file,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function renameFile(oldPath, newPath, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "renameFile",
|
||||
oldPath,
|
||||
newPath,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
async function exists(path, options = {}) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Fs",
|
||||
message: {
|
||||
cmd: "exists",
|
||||
path,
|
||||
options
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
BaseDirectory,
|
||||
BaseDirectory as Dir,
|
||||
copyFile,
|
||||
createDir,
|
||||
exists,
|
||||
readBinaryFile,
|
||||
readDir,
|
||||
readTextFile,
|
||||
removeDir,
|
||||
removeFile,
|
||||
renameFile,
|
||||
writeBinaryFile,
|
||||
writeTextFile as writeFile,
|
||||
writeTextFile
|
||||
};
|
97
src/globalShortcut.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/globalShortcut.ts
|
||||
async function register(shortcut, handler) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "GlobalShortcut",
|
||||
message: {
|
||||
cmd: "register",
|
||||
shortcut,
|
||||
handler: transformCallback(handler)
|
||||
}
|
||||
});
|
||||
}
|
||||
async function registerAll(shortcuts, handler) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "GlobalShortcut",
|
||||
message: {
|
||||
cmd: "registerAll",
|
||||
shortcuts,
|
||||
handler: transformCallback(handler)
|
||||
}
|
||||
});
|
||||
}
|
||||
async function isRegistered(shortcut) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "GlobalShortcut",
|
||||
message: {
|
||||
cmd: "isRegistered",
|
||||
shortcut
|
||||
}
|
||||
});
|
||||
}
|
||||
async function unregister(shortcut) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "GlobalShortcut",
|
||||
message: {
|
||||
cmd: "unregister",
|
||||
shortcut
|
||||
}
|
||||
});
|
||||
}
|
||||
async function unregisterAll() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "GlobalShortcut",
|
||||
message: {
|
||||
cmd: "unregisterAll"
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
isRegistered,
|
||||
register,
|
||||
registerAll,
|
||||
unregister,
|
||||
unregisterAll
|
||||
};
|
219
src/http.js
Normal file
|
@ -0,0 +1,219 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/http.ts
|
||||
var ResponseType = /* @__PURE__ */ ((ResponseType2) => {
|
||||
ResponseType2[ResponseType2["JSON"] = 1] = "JSON";
|
||||
ResponseType2[ResponseType2["Text"] = 2] = "Text";
|
||||
ResponseType2[ResponseType2["Binary"] = 3] = "Binary";
|
||||
return ResponseType2;
|
||||
})(ResponseType || {});
|
||||
var Body = class {
|
||||
constructor(type, payload) {
|
||||
this.type = type;
|
||||
this.payload = payload;
|
||||
}
|
||||
static form(data) {
|
||||
const form = {};
|
||||
const append = (key, v) => {
|
||||
if (v !== null) {
|
||||
let r;
|
||||
if (typeof v === "string") {
|
||||
r = v;
|
||||
} else if (v instanceof Uint8Array || Array.isArray(v)) {
|
||||
r = Array.from(v);
|
||||
} else if (v instanceof File) {
|
||||
r = { file: v.name, mime: v.type, fileName: v.name };
|
||||
} else if (typeof v.file === "string") {
|
||||
r = { file: v.file, mime: v.mime, fileName: v.fileName };
|
||||
} else {
|
||||
r = { file: Array.from(v.file), mime: v.mime, fileName: v.fileName };
|
||||
}
|
||||
form[String(key)] = r;
|
||||
}
|
||||
};
|
||||
if (data instanceof FormData) {
|
||||
for (const [key, value] of data) {
|
||||
append(key, value);
|
||||
}
|
||||
} else {
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
append(key, value);
|
||||
}
|
||||
}
|
||||
return new Body("Form", form);
|
||||
}
|
||||
static json(data) {
|
||||
return new Body("Json", data);
|
||||
}
|
||||
static text(value) {
|
||||
return new Body("Text", value);
|
||||
}
|
||||
static bytes(bytes) {
|
||||
return new Body(
|
||||
"Bytes",
|
||||
Array.from(bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes)
|
||||
);
|
||||
}
|
||||
};
|
||||
var Response = class {
|
||||
constructor(response) {
|
||||
this.url = response.url;
|
||||
this.status = response.status;
|
||||
this.ok = this.status >= 200 && this.status < 300;
|
||||
this.headers = response.headers;
|
||||
this.rawHeaders = response.rawHeaders;
|
||||
this.data = response.data;
|
||||
}
|
||||
};
|
||||
var Client = class {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
async drop() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Http",
|
||||
message: {
|
||||
cmd: "dropClient",
|
||||
client: this.id
|
||||
}
|
||||
});
|
||||
}
|
||||
async request(options) {
|
||||
const jsonResponse = !options.responseType || options.responseType === 1 /* JSON */;
|
||||
if (jsonResponse) {
|
||||
options.responseType = 2 /* Text */;
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Http",
|
||||
message: {
|
||||
cmd: "httpRequest",
|
||||
client: this.id,
|
||||
options
|
||||
}
|
||||
}).then((res) => {
|
||||
const response = new Response(res);
|
||||
if (jsonResponse) {
|
||||
try {
|
||||
response.data = JSON.parse(response.data);
|
||||
} catch (e) {
|
||||
if (response.ok && response.data === "") {
|
||||
response.data = {};
|
||||
} else if (response.ok) {
|
||||
throw Error(
|
||||
`Failed to parse response \`${response.data}\` as JSON: ${e};
|
||||
try setting the \`responseType\` option to \`ResponseType.Text\` or \`ResponseType.Binary\` if the API does not return a JSON response.`
|
||||
);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
});
|
||||
}
|
||||
async get(url, options) {
|
||||
return this.request({
|
||||
method: "GET",
|
||||
url,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async post(url, body, options) {
|
||||
return this.request({
|
||||
method: "POST",
|
||||
url,
|
||||
body,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async put(url, body, options) {
|
||||
return this.request({
|
||||
method: "PUT",
|
||||
url,
|
||||
body,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async patch(url, options) {
|
||||
return this.request({
|
||||
method: "PATCH",
|
||||
url,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async delete(url, options) {
|
||||
return this.request({
|
||||
method: "DELETE",
|
||||
url,
|
||||
...options
|
||||
});
|
||||
}
|
||||
};
|
||||
async function getClient(options) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Http",
|
||||
message: {
|
||||
cmd: "createClient",
|
||||
options
|
||||
}
|
||||
}).then((id) => new Client(id));
|
||||
}
|
||||
var defaultClient = null;
|
||||
async function fetch(url, options) {
|
||||
if (defaultClient === null) {
|
||||
defaultClient = await getClient();
|
||||
}
|
||||
return defaultClient.request({
|
||||
url,
|
||||
method: options?.method ?? "GET",
|
||||
...options
|
||||
});
|
||||
}
|
||||
export {
|
||||
Body,
|
||||
Client,
|
||||
Response,
|
||||
ResponseType,
|
||||
fetch,
|
||||
getClient
|
||||
};
|
2414
src/index.js
Normal file
36
src/lib.rs
|
@ -4,21 +4,49 @@ use wasm_bindgen::JsValue;
|
|||
pub mod app;
|
||||
#[cfg(feature = "clipboard")]
|
||||
pub mod clipboard;
|
||||
#[cfg(feature = "dialog")]
|
||||
pub mod dialog;
|
||||
#[cfg(feature = "event")]
|
||||
pub mod event;
|
||||
#[cfg(feature = "mocks")]
|
||||
pub mod mocks;
|
||||
#[cfg(feature = "process")]
|
||||
pub mod process;
|
||||
#[cfg(feature = "tauri")]
|
||||
pub mod tauri;
|
||||
#[cfg(feature = "updater")]
|
||||
pub mod updater;
|
||||
#[cfg(feature = "window")]
|
||||
pub mod window;
|
||||
#[cfg(feature = "notification")]
|
||||
pub mod notification;
|
||||
#[cfg(feature = "os")]
|
||||
pub mod os;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Serde(#[from] serde_wasm_bindgen::Error),
|
||||
#[error("{0:?}")]
|
||||
Other(JsValue),
|
||||
#[error("{0}")]
|
||||
Serde(String),
|
||||
#[error("Unknown Theme \"{0}\". Expected one of \"light\",\"dark\"")]
|
||||
UnknownTheme(String),
|
||||
#[error("Invalid Url {0}")]
|
||||
InvalidUrl(#[from] url::ParseError),
|
||||
#[error("Invalid Version {0}")]
|
||||
InvalidVersion(#[from] semver::Error),
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<serde_wasm_bindgen::Error> for Error {
|
||||
fn from(e: serde_wasm_bindgen::Error) -> Self {
|
||||
Self::Serde(format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsValue> for Error {
|
||||
fn from(e: JsValue) -> Self {
|
||||
Self::Serde(format!("{:?}", e))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
|
@ -55,7 +55,7 @@ mod inner {
|
|||
JsValue,
|
||||
};
|
||||
|
||||
#[wasm_bindgen(module = "/dist/mocks.js")]
|
||||
#[wasm_bindgen(module = "/src/mocks.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(variadic)]
|
||||
pub fn mockWindows(current: &str, rest: JsValue);
|
||||
|
|
70
src/notification.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/notification.ts
|
||||
async function isPermissionGranted() {
|
||||
if (window.Notification.permission !== "default") {
|
||||
return Promise.resolve(window.Notification.permission === "granted");
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Notification",
|
||||
message: {
|
||||
cmd: "isNotificationPermissionGranted"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function requestPermission() {
|
||||
return window.Notification.requestPermission();
|
||||
}
|
||||
function sendNotification(options) {
|
||||
if (typeof options === "string") {
|
||||
new window.Notification(options);
|
||||
} else {
|
||||
new window.Notification(options.title, options);
|
||||
}
|
||||
}
|
||||
export {
|
||||
isPermissionGranted,
|
||||
requestPermission,
|
||||
sendNotification
|
||||
};
|
84
src/notification.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
pub async fn is_permission_granted() -> crate::Result<bool> {
|
||||
let raw = inner::isPermissionGranted().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
pub async fn request_permission() -> crate::Result<Permission> {
|
||||
let raw = inner::requestPermission().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Permission {
|
||||
#[default]
|
||||
Default,
|
||||
Granted,
|
||||
Denied,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Permission {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
match String::deserialize(deserializer)?.as_str() {
|
||||
"default" => Ok(Permission::Default),
|
||||
"granted" => Ok(Permission::Granted),
|
||||
"denied" => Ok(Permission::Denied),
|
||||
_ => Err(serde::de::Error::custom(
|
||||
"expected one of default, granted, denied",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub struct Notification<'a> {
|
||||
body: Option<&'a str>,
|
||||
title: Option<&'a str>,
|
||||
icon: Option<&'a str>
|
||||
}
|
||||
|
||||
impl<'a> Notification<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn set_title(&mut self, title: &'a str) {
|
||||
self.title = Some(title);
|
||||
}
|
||||
|
||||
pub fn set_body(&mut self, body: &'a str) {
|
||||
self.body = Some(body);
|
||||
}
|
||||
|
||||
pub fn set_icon(&mut self, icon: &'a str) {
|
||||
self.icon = Some(icon);
|
||||
}
|
||||
|
||||
pub fn show(&self) -> crate::Result<()> {
|
||||
inner::sendNotification(serde_wasm_bindgen::to_value(&self)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
#[wasm_bindgen(module = "/src/notification.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn isPermissionGranted() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn requestPermission() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn sendNotification(notification: JsValue) -> Result<(), JsValue>;
|
||||
}
|
||||
}
|
98
src/os.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
// tauri/tooling/api/src/helpers/os-check.ts
|
||||
function isWindows() {
|
||||
return navigator.appVersion.includes("Win");
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/os.ts
|
||||
var EOL = isWindows() ? "\r\n" : "\n";
|
||||
async function platform() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Os",
|
||||
message: {
|
||||
cmd: "platform"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function version() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Os",
|
||||
message: {
|
||||
cmd: "version"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function type() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Os",
|
||||
message: {
|
||||
cmd: "osType"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function arch() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Os",
|
||||
message: {
|
||||
cmd: "arch"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function tempdir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Os",
|
||||
message: {
|
||||
cmd: "tempdir"
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
EOL,
|
||||
arch,
|
||||
platform,
|
||||
tempdir,
|
||||
type,
|
||||
version
|
||||
};
|
111
src/os.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use std::path::{PathBuf};
|
||||
use semver::Version;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum Arch {
|
||||
#[serde(rename = "x86")]
|
||||
X86,
|
||||
#[serde(rename = "x86_64")]
|
||||
X86_64,
|
||||
#[serde(rename = "arm")]
|
||||
Arm,
|
||||
#[serde(rename = "aarch64")]
|
||||
Aarch64,
|
||||
#[serde(rename = "mips")]
|
||||
Mips,
|
||||
#[serde(rename = "mips64")]
|
||||
Mips64,
|
||||
#[serde(rename = "powerpc")]
|
||||
Powerpc,
|
||||
#[serde(rename = "powerpc64")]
|
||||
Powerpc64,
|
||||
#[serde(rename = "riscv64")]
|
||||
Riscv64,
|
||||
#[serde(rename = "s390x")]
|
||||
S390x,
|
||||
#[serde(rename = "sparc64")]
|
||||
Sparc64
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum Platform {
|
||||
#[serde(rename = "linux")]
|
||||
Linux,
|
||||
#[serde(rename = "darwin")]
|
||||
Darwin,
|
||||
#[serde(rename = "ios")]
|
||||
Ios,
|
||||
#[serde(rename = "freebsd")]
|
||||
Freebsd,
|
||||
#[serde(rename = "dragonfly")]
|
||||
Dragonfly,
|
||||
#[serde(rename = "netbsd")]
|
||||
Netbsd,
|
||||
#[serde(rename = "openbsd")]
|
||||
Openbsd,
|
||||
#[serde(rename = "solaris")]
|
||||
Solaris,
|
||||
#[serde(rename = "android")]
|
||||
Android,
|
||||
#[serde(rename = "win32")]
|
||||
Win32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum OsKind {
|
||||
#[serde(rename = "Linux")]
|
||||
Linux,
|
||||
#[serde(rename = "Darwin")]
|
||||
Darwin,
|
||||
#[serde(rename = "Windows_NT")]
|
||||
WindowsNt,
|
||||
}
|
||||
|
||||
pub async fn arch() -> crate::Result<Arch> {
|
||||
let raw = inner::arch().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
pub async fn platform() -> crate::Result<Platform> {
|
||||
let raw = inner::platform().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
pub async fn tempdir() -> crate::Result<PathBuf> {
|
||||
let raw = inner::tempdir().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
pub async fn kind() -> crate::Result<OsKind> {
|
||||
let raw = inner::kind().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
pub async fn version() -> crate::Result<Version> {
|
||||
let raw = inner::version().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(raw)?)
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "/src/os.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn arch() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn platform() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn tempdir() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch, js_name = "type")]
|
||||
pub async fn kind() -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn version() -> Result<JsValue, JsValue>;
|
||||
}
|
||||
}
|
418
src/path.js
Normal file
|
@ -0,0 +1,418 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve2, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve2(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/fs.ts
|
||||
var BaseDirectory = /* @__PURE__ */ ((BaseDirectory2) => {
|
||||
BaseDirectory2[BaseDirectory2["Audio"] = 1] = "Audio";
|
||||
BaseDirectory2[BaseDirectory2["Cache"] = 2] = "Cache";
|
||||
BaseDirectory2[BaseDirectory2["Config"] = 3] = "Config";
|
||||
BaseDirectory2[BaseDirectory2["Data"] = 4] = "Data";
|
||||
BaseDirectory2[BaseDirectory2["LocalData"] = 5] = "LocalData";
|
||||
BaseDirectory2[BaseDirectory2["Desktop"] = 6] = "Desktop";
|
||||
BaseDirectory2[BaseDirectory2["Document"] = 7] = "Document";
|
||||
BaseDirectory2[BaseDirectory2["Download"] = 8] = "Download";
|
||||
BaseDirectory2[BaseDirectory2["Executable"] = 9] = "Executable";
|
||||
BaseDirectory2[BaseDirectory2["Font"] = 10] = "Font";
|
||||
BaseDirectory2[BaseDirectory2["Home"] = 11] = "Home";
|
||||
BaseDirectory2[BaseDirectory2["Picture"] = 12] = "Picture";
|
||||
BaseDirectory2[BaseDirectory2["Public"] = 13] = "Public";
|
||||
BaseDirectory2[BaseDirectory2["Runtime"] = 14] = "Runtime";
|
||||
BaseDirectory2[BaseDirectory2["Template"] = 15] = "Template";
|
||||
BaseDirectory2[BaseDirectory2["Video"] = 16] = "Video";
|
||||
BaseDirectory2[BaseDirectory2["Resource"] = 17] = "Resource";
|
||||
BaseDirectory2[BaseDirectory2["App"] = 18] = "App";
|
||||
BaseDirectory2[BaseDirectory2["Log"] = 19] = "Log";
|
||||
BaseDirectory2[BaseDirectory2["Temp"] = 20] = "Temp";
|
||||
BaseDirectory2[BaseDirectory2["AppConfig"] = 21] = "AppConfig";
|
||||
BaseDirectory2[BaseDirectory2["AppData"] = 22] = "AppData";
|
||||
BaseDirectory2[BaseDirectory2["AppLocalData"] = 23] = "AppLocalData";
|
||||
BaseDirectory2[BaseDirectory2["AppCache"] = 24] = "AppCache";
|
||||
BaseDirectory2[BaseDirectory2["AppLog"] = 25] = "AppLog";
|
||||
return BaseDirectory2;
|
||||
})(BaseDirectory || {});
|
||||
|
||||
// tauri/tooling/api/src/helpers/os-check.ts
|
||||
function isWindows() {
|
||||
return navigator.appVersion.includes("Win");
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/path.ts
|
||||
async function appDir() {
|
||||
return appConfigDir();
|
||||
}
|
||||
async function appConfigDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 21 /* AppConfig */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function appDataDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 22 /* AppData */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function appLocalDataDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 23 /* AppLocalData */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function appCacheDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 24 /* AppCache */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function audioDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 1 /* Audio */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function cacheDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 2 /* Cache */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function configDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 3 /* Config */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function dataDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 4 /* Data */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function desktopDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 6 /* Desktop */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function documentDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 7 /* Document */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function downloadDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 8 /* Download */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function executableDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 9 /* Executable */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function fontDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 10 /* Font */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function homeDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 11 /* Home */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function localDataDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 5 /* LocalData */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function pictureDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 12 /* Picture */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function publicDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 13 /* Public */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function resourceDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 17 /* Resource */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function resolveResource(resourcePath) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: resourcePath,
|
||||
directory: 17 /* Resource */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function runtimeDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 14 /* Runtime */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function templateDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 15 /* Template */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function videoDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 16 /* Video */
|
||||
}
|
||||
});
|
||||
}
|
||||
async function logDir() {
|
||||
return appLogDir();
|
||||
}
|
||||
async function appLogDir() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolvePath",
|
||||
path: "",
|
||||
directory: 25 /* AppLog */
|
||||
}
|
||||
});
|
||||
}
|
||||
var sep = isWindows() ? "\\" : "/";
|
||||
var delimiter = isWindows() ? ";" : ":";
|
||||
async function resolve(...paths) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "resolve",
|
||||
paths
|
||||
}
|
||||
});
|
||||
}
|
||||
async function normalize(path) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "normalize",
|
||||
path
|
||||
}
|
||||
});
|
||||
}
|
||||
async function join(...paths) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "join",
|
||||
paths
|
||||
}
|
||||
});
|
||||
}
|
||||
async function dirname(path) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "dirname",
|
||||
path
|
||||
}
|
||||
});
|
||||
}
|
||||
async function extname(path) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "extname",
|
||||
path
|
||||
}
|
||||
});
|
||||
}
|
||||
async function basename(path, ext) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "basename",
|
||||
path,
|
||||
ext
|
||||
}
|
||||
});
|
||||
}
|
||||
async function isAbsolute(path) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Path",
|
||||
message: {
|
||||
cmd: "isAbsolute",
|
||||
path
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
BaseDirectory,
|
||||
appCacheDir,
|
||||
appConfigDir,
|
||||
appDataDir,
|
||||
appDir,
|
||||
appLocalDataDir,
|
||||
appLogDir,
|
||||
audioDir,
|
||||
basename,
|
||||
cacheDir,
|
||||
configDir,
|
||||
dataDir,
|
||||
delimiter,
|
||||
desktopDir,
|
||||
dirname,
|
||||
documentDir,
|
||||
downloadDir,
|
||||
executableDir,
|
||||
extname,
|
||||
fontDir,
|
||||
homeDir,
|
||||
isAbsolute,
|
||||
join,
|
||||
localDataDir,
|
||||
logDir,
|
||||
normalize,
|
||||
pictureDir,
|
||||
publicDir,
|
||||
resolve,
|
||||
resolveResource,
|
||||
resourceDir,
|
||||
runtimeDir,
|
||||
sep,
|
||||
templateDir,
|
||||
videoDir
|
||||
};
|
65
src/process.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/process.ts
|
||||
async function exit(exitCode = 0) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Process",
|
||||
message: {
|
||||
cmd: "exit",
|
||||
exitCode
|
||||
}
|
||||
});
|
||||
}
|
||||
async function relaunch() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Process",
|
||||
message: {
|
||||
cmd: "relaunch"
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
exit,
|
||||
relaunch
|
||||
};
|
18
src/process.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
pub async fn exit(exit_code: u32) -> ! {
|
||||
inner::exit(exit_code).await;
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn relaunch() {
|
||||
inner::relaunch();
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(module = "/src/process.js")]
|
||||
extern "C" {
|
||||
pub async fn exit(exitCode: u32);
|
||||
pub fn relaunch();
|
||||
}
|
||||
}
|
230
src/shell.js
Normal file
|
@ -0,0 +1,230 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once) {
|
||||
Reflect.deleteProperty(window, prop);
|
||||
}
|
||||
return callback?.(result);
|
||||
},
|
||||
writable: false,
|
||||
configurable: true
|
||||
});
|
||||
return identifier;
|
||||
}
|
||||
async function invoke(cmd, args = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = transformCallback((e) => {
|
||||
resolve(e);
|
||||
Reflect.deleteProperty(window, `_${error}`);
|
||||
}, true);
|
||||
const error = transformCallback((e) => {
|
||||
reject(e);
|
||||
Reflect.deleteProperty(window, `_${callback}`);
|
||||
}, true);
|
||||
window.__TAURI_IPC__({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/helpers/tauri.ts
|
||||
async function invokeTauriCommand(command) {
|
||||
return invoke("tauri", command);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/shell.ts
|
||||
async function execute(onEvent, program, args = [], options) {
|
||||
if (typeof args === "object") {
|
||||
Object.freeze(args);
|
||||
}
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Shell",
|
||||
message: {
|
||||
cmd: "execute",
|
||||
program,
|
||||
args,
|
||||
options,
|
||||
onEventFn: transformCallback(onEvent)
|
||||
}
|
||||
});
|
||||
}
|
||||
var EventEmitter = class {
|
||||
constructor() {
|
||||
this.eventListeners = /* @__PURE__ */ Object.create(null);
|
||||
}
|
||||
addListener(eventName, listener) {
|
||||
return this.on(eventName, listener);
|
||||
}
|
||||
removeListener(eventName, listener) {
|
||||
return this.off(eventName, listener);
|
||||
}
|
||||
on(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
this.eventListeners[eventName].push(listener);
|
||||
} else {
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
once(eventName, listener) {
|
||||
const wrapper = (...args) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
listener(...args);
|
||||
};
|
||||
return this.addListener(eventName, wrapper);
|
||||
}
|
||||
off(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
this.eventListeners[eventName] = this.eventListeners[eventName].filter(
|
||||
(l) => l !== listener
|
||||
);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
removeAllListeners(event) {
|
||||
if (event) {
|
||||
delete this.eventListeners[event];
|
||||
} else {
|
||||
this.eventListeners = /* @__PURE__ */ Object.create(null);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
emit(eventName, ...args) {
|
||||
if (eventName in this.eventListeners) {
|
||||
const listeners = this.eventListeners[eventName];
|
||||
for (const listener of listeners)
|
||||
listener(...args);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
listenerCount(eventName) {
|
||||
if (eventName in this.eventListeners)
|
||||
return this.eventListeners[eventName].length;
|
||||
return 0;
|
||||
}
|
||||
prependListener(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
this.eventListeners[eventName].unshift(listener);
|
||||
} else {
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
prependOnceListener(eventName, listener) {
|
||||
const wrapper = (...args) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
listener(...args);
|
||||
};
|
||||
return this.prependListener(eventName, wrapper);
|
||||
}
|
||||
};
|
||||
var Child = class {
|
||||
constructor(pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
async write(data) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Shell",
|
||||
message: {
|
||||
cmd: "stdinWrite",
|
||||
pid: this.pid,
|
||||
buffer: typeof data === "string" ? data : Array.from(data)
|
||||
}
|
||||
});
|
||||
}
|
||||
async kill() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Shell",
|
||||
message: {
|
||||
cmd: "killChild",
|
||||
pid: this.pid
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var Command = class extends EventEmitter {
|
||||
constructor(program, args = [], options) {
|
||||
super();
|
||||
this.stdout = new EventEmitter();
|
||||
this.stderr = new EventEmitter();
|
||||
this.program = program;
|
||||
this.args = typeof args === "string" ? [args] : args;
|
||||
this.options = options ?? {};
|
||||
}
|
||||
static sidecar(program, args = [], options) {
|
||||
const instance = new Command(program, args, options);
|
||||
instance.options.sidecar = true;
|
||||
return instance;
|
||||
}
|
||||
async spawn() {
|
||||
return execute(
|
||||
(event) => {
|
||||
switch (event.event) {
|
||||
case "Error":
|
||||
this.emit("error", event.payload);
|
||||
break;
|
||||
case "Terminated":
|
||||
this.emit("close", event.payload);
|
||||
break;
|
||||
case "Stdout":
|
||||
this.stdout.emit("data", event.payload);
|
||||
break;
|
||||
case "Stderr":
|
||||
this.stderr.emit("data", event.payload);
|
||||
break;
|
||||
}
|
||||
},
|
||||
this.program,
|
||||
this.args,
|
||||
this.options
|
||||
).then((pid) => new Child(pid));
|
||||
}
|
||||
async execute() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.on("error", reject);
|
||||
const stdout = [];
|
||||
const stderr = [];
|
||||
this.stdout.on("data", (line) => {
|
||||
stdout.push(line);
|
||||
});
|
||||
this.stderr.on("data", (line) => {
|
||||
stderr.push(line);
|
||||
});
|
||||
this.on("close", (payload) => {
|
||||
resolve({
|
||||
code: payload.code,
|
||||
signal: payload.signal,
|
||||
stdout: stdout.join("\n"),
|
||||
stderr: stderr.join("\n")
|
||||
});
|
||||
});
|
||||
this.spawn().catch(reject);
|
||||
});
|
||||
}
|
||||
};
|
||||
async function open(path, openWith) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Shell",
|
||||
message: {
|
||||
cmd: "open",
|
||||
path,
|
||||
with: openWith
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
Child,
|
||||
Command,
|
||||
EventEmitter,
|
||||
open
|
||||
};
|
42
src/tauri.rs
|
@ -36,14 +36,10 @@ use url::Url;
|
|||
///
|
||||
/// @return the URL that can be used as source on the webview.
|
||||
#[inline(always)]
|
||||
pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> Url {
|
||||
Url::parse(
|
||||
&inner::convertFileSrc(file_path, protocol)
|
||||
.await
|
||||
.as_string()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> crate::Result<Url> {
|
||||
let js_val = inner::convertFileSrc(file_path, protocol).await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
/// Sends a message to the backend.
|
||||
|
@ -66,9 +62,8 @@ pub async fn convert_file_src(file_path: &str, protocol: Option<&str>) -> Url {
|
|||
/// @return A promise resolving or rejecting to the backend response.
|
||||
#[inline(always)]
|
||||
pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> crate::Result<R> {
|
||||
let res = inner::invoke(cmd, serde_wasm_bindgen::to_value(args).unwrap()).await;
|
||||
let raw = inner::invoke(cmd, serde_wasm_bindgen::to_value(args)?).await?;
|
||||
|
||||
let raw = res.map_err(crate::Error::Other)?;
|
||||
serde_wasm_bindgen::from_value(raw).map_err(Into::into)
|
||||
}
|
||||
|
||||
|
@ -77,24 +72,35 @@ pub async fn invoke<A: Serialize, R: DeserializeOwned>(cmd: &str, args: &A) -> c
|
|||
///
|
||||
/// @return A unique identifier associated with the callback function.
|
||||
#[inline(always)]
|
||||
pub async fn transform_callback<T: DeserializeOwned>(callback: &dyn Fn(T), once: bool) -> f64 {
|
||||
inner::transformCallback(
|
||||
pub async fn transform_callback<T: DeserializeOwned>(
|
||||
callback: &dyn Fn(T),
|
||||
once: bool,
|
||||
) -> crate::Result<f64> {
|
||||
let js_val = inner::transformCallback(
|
||||
&|raw| callback(serde_wasm_bindgen::from_value(raw).unwrap()),
|
||||
once,
|
||||
)
|
||||
.await
|
||||
.as_f64()
|
||||
.unwrap()
|
||||
.await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
|
||||
|
||||
#[wasm_bindgen(module = "/dist/tauri.js")]
|
||||
#[wasm_bindgen(module = "/src/tauri.js")]
|
||||
extern "C" {
|
||||
pub async fn convertFileSrc(filePath: &str, protocol: Option<&str>) -> JsValue;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn convertFileSrc(
|
||||
filePath: &str,
|
||||
protocol: Option<&str>,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>;
|
||||
pub async fn transformCallback(callback: &dyn Fn(JsValue), once: bool) -> JsValue;
|
||||
#[wasm_bindgen(catch)]
|
||||
pub async fn transformCallback(
|
||||
callback: &dyn Fn(JsValue),
|
||||
once: bool,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
}
|
||||
}
|
||||
|
|
1004
src/window.js
Normal file
825
src/window.rs
Normal file
|
@ -0,0 +1,825 @@
|
|||
use crate::{event::Event, Error};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::fmt::Display;
|
||||
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Theme {
|
||||
Light,
|
||||
Dark,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TitleBarStyle {
|
||||
Visible,
|
||||
Transparent,
|
||||
Overlay,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum UserAttentionType {
|
||||
Critical = 1,
|
||||
Informational,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Position {
|
||||
Physical(PhysicalPosition),
|
||||
Logical(LogicalPosition),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Size {
|
||||
Physical(PhysicalSize),
|
||||
Logical(LogicalSize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CursorIcon {
|
||||
Default,
|
||||
Crosshair,
|
||||
Hand,
|
||||
Arrow,
|
||||
Move,
|
||||
Text,
|
||||
Wait,
|
||||
Help,
|
||||
Progress,
|
||||
// something cannot be done
|
||||
NotAllowed,
|
||||
ContextMenu,
|
||||
Cell,
|
||||
VerticalText,
|
||||
Alias,
|
||||
Copy,
|
||||
NoDrop,
|
||||
// something can be grabbed
|
||||
Grab,
|
||||
/// something is grabbed
|
||||
Grabbing,
|
||||
AllScroll,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
// edge is to be moved
|
||||
EResize,
|
||||
NResize,
|
||||
NeResize,
|
||||
NwResize,
|
||||
SResize,
|
||||
SeResize,
|
||||
SwResize,
|
||||
WResize,
|
||||
EwResize,
|
||||
NsResize,
|
||||
NeswResize,
|
||||
NwseResize,
|
||||
ColResize,
|
||||
RowResize,
|
||||
}
|
||||
|
||||
impl Display for CursorIcon {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
CursorIcon::Default => write!(f, "default"),
|
||||
CursorIcon::Crosshair => write!(f, "crosshair"),
|
||||
CursorIcon::Hand => write!(f, "hand"),
|
||||
CursorIcon::Arrow => write!(f, "arrow"),
|
||||
CursorIcon::Move => write!(f, "move"),
|
||||
CursorIcon::Text => write!(f, "text"),
|
||||
CursorIcon::Wait => write!(f, "wait"),
|
||||
CursorIcon::Help => write!(f, "help"),
|
||||
CursorIcon::Progress => write!(f, "progress"),
|
||||
CursorIcon::NotAllowed => write!(f, "notAllowed"),
|
||||
CursorIcon::ContextMenu => write!(f, "contextMenu"),
|
||||
CursorIcon::Cell => write!(f, "cell"),
|
||||
CursorIcon::VerticalText => write!(f, "verticalText"),
|
||||
CursorIcon::Alias => write!(f, "alias"),
|
||||
CursorIcon::Copy => write!(f, "copy"),
|
||||
CursorIcon::NoDrop => write!(f, "noDrop"),
|
||||
CursorIcon::Grab => write!(f, "grab"),
|
||||
CursorIcon::Grabbing => write!(f, "grabbing"),
|
||||
CursorIcon::AllScroll => write!(f, "allScroll"),
|
||||
CursorIcon::ZoomIn => write!(f, "zoomIn"),
|
||||
CursorIcon::ZoomOut => write!(f, "zoomOut"),
|
||||
CursorIcon::EResize => write!(f, "eResize"),
|
||||
CursorIcon::NResize => write!(f, "nResize"),
|
||||
CursorIcon::NeResize => write!(f, "neResize"),
|
||||
CursorIcon::NwResize => write!(f, "nwResize"),
|
||||
CursorIcon::SResize => write!(f, "sResize"),
|
||||
CursorIcon::SeResize => write!(f, "seResize"),
|
||||
CursorIcon::SwResize => write!(f, "swResize"),
|
||||
CursorIcon::WResize => write!(f, "wResize"),
|
||||
CursorIcon::EwResize => write!(f, "ewResize"),
|
||||
CursorIcon::NsResize => write!(f, "nsResize"),
|
||||
CursorIcon::NeswResize => write!(f, "neswResize"),
|
||||
CursorIcon::NwseResize => write!(f, "nwseResize"),
|
||||
CursorIcon::ColResize => write!(f, "colResize"),
|
||||
CursorIcon::RowResize => write!(f, "rowResize"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct WebviewWindow(inner::WebviewWindow);
|
||||
|
||||
impl WebviewWindow {
|
||||
pub fn new(label: &str, options: ()) -> Self {
|
||||
Self(inner::WebviewWindow::new(label, options))
|
||||
}
|
||||
|
||||
pub fn get_by_label(label: &str) -> Option<Self> {
|
||||
inner::WebviewWindow::getByLabel(label).map(Self)
|
||||
}
|
||||
|
||||
pub fn label(&self) -> String {
|
||||
self.0.label()
|
||||
}
|
||||
|
||||
pub async fn scale_factor(&self) -> crate::Result<f64> {
|
||||
let js_val = self.0.scaleFactor().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn inner_position(&self) -> crate::Result<PhysicalPosition> {
|
||||
Ok(PhysicalPosition(
|
||||
self.0.innerPosition().await?.unchecked_into(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn outer_position(&self) -> crate::Result<PhysicalPosition> {
|
||||
Ok(PhysicalPosition(
|
||||
self.0.outerPosition().await?.unchecked_into(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn inner_size(&self) -> crate::Result<PhysicalSize> {
|
||||
Ok(PhysicalSize(self.0.innerSize().await?.unchecked_into()))
|
||||
}
|
||||
|
||||
pub async fn outer_size(&self) -> crate::Result<PhysicalSize> {
|
||||
Ok(PhysicalSize(self.0.outerSize().await?.unchecked_into()))
|
||||
}
|
||||
|
||||
pub async fn is_fullscreen(&self) -> crate::Result<bool> {
|
||||
let js_val = self.0.isFullscreen().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn is_maximized(&self) -> crate::Result<bool> {
|
||||
let js_val = self.0.isMaximized().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn is_decorated(&self) -> crate::Result<bool> {
|
||||
let js_val = self.0.isDecorated().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn is_resizable(&self) -> crate::Result<bool> {
|
||||
let js_val = self.0.isResizable().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn is_visible(&self) -> crate::Result<bool> {
|
||||
let js_val = self.0.isVisible().await?;
|
||||
|
||||
Ok(serde_wasm_bindgen::from_value(js_val)?)
|
||||
}
|
||||
|
||||
pub async fn theme(&self) -> crate::Result<Theme> {
|
||||
let js_val = self.0.theme().await?;
|
||||
|
||||
let str = serde_wasm_bindgen::from_value::<String>(js_val)?;
|
||||
|
||||
match str.as_str() {
|
||||
"light" => Ok(Theme::Light),
|
||||
"dark" => Ok(Theme::Dark),
|
||||
_ => Err(Error::UnknownTheme(str)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn center(&self) -> crate::Result<()> {
|
||||
Ok(self.0.center().await?)
|
||||
}
|
||||
|
||||
pub async fn request_user_attention(
|
||||
&self,
|
||||
request_type: UserAttentionType,
|
||||
) -> crate::Result<()> {
|
||||
Ok(self.0.requestUserAttention(request_type as u32).await?)
|
||||
}
|
||||
|
||||
pub async fn set_resizable(&self, resizable: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setResizable(resizable).await?)
|
||||
}
|
||||
|
||||
pub async fn set_title(&self, title: impl AsRef<str>) -> crate::Result<()> {
|
||||
Ok(self.0.setTitle(title.as_ref()).await?)
|
||||
}
|
||||
|
||||
pub async fn maximize(&self) -> crate::Result<()> {
|
||||
Ok(self.0.maximize().await?)
|
||||
}
|
||||
|
||||
pub async fn unmaximize(&self) -> crate::Result<()> {
|
||||
Ok(self.0.unmaximize().await?)
|
||||
}
|
||||
|
||||
pub async fn toggle_maximize(&self) -> crate::Result<()> {
|
||||
Ok(self.0.toggleMaximize().await?)
|
||||
}
|
||||
|
||||
pub async fn minimize(&self) -> crate::Result<()> {
|
||||
Ok(self.0.minimize().await?)
|
||||
}
|
||||
|
||||
pub async fn unminimize(&self) -> crate::Result<()> {
|
||||
Ok(self.0.unminimize().await?)
|
||||
}
|
||||
|
||||
pub async fn show(&self) -> crate::Result<()> {
|
||||
Ok(self.0.show().await?)
|
||||
}
|
||||
|
||||
pub async fn hide(&self) -> crate::Result<()> {
|
||||
Ok(self.0.hide().await?)
|
||||
}
|
||||
|
||||
pub async fn close(&self) -> crate::Result<()> {
|
||||
Ok(self.0.close().await?)
|
||||
}
|
||||
|
||||
pub async fn set_decorations(&self, decorations: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setDecorations(decorations).await?)
|
||||
}
|
||||
|
||||
pub async fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setAlwaysOnTop(always_on_top).await?)
|
||||
}
|
||||
|
||||
pub async fn set_size(&self, size: Size) -> crate::Result<()> {
|
||||
match size {
|
||||
Size::Physical(size) => self.0.setSizePhysical(size.0).await?,
|
||||
Size::Logical(size) => self.0.setSizeLogical(size.0).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_min_size(&self, size: Option<Size>) -> crate::Result<()> {
|
||||
match size {
|
||||
None => self.0.setMinSizePhysical(None).await?,
|
||||
Some(Size::Physical(size)) => self.0.setMinSizePhysical(Some(size.0)).await?,
|
||||
Some(Size::Logical(size)) => self.0.setMinSizeLogical(Some(size.0)).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_max_size(&self, size: Option<Size>) -> crate::Result<()> {
|
||||
match size {
|
||||
None => self.0.setMaxSizePhysical(None).await?,
|
||||
Some(Size::Physical(size)) => self.0.setMaxSizePhysical(Some(size.0)).await?,
|
||||
Some(Size::Logical(size)) => self.0.setMaxSizeLogical(Some(size.0)).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_position(&self, position: Position) -> crate::Result<()> {
|
||||
match position {
|
||||
Position::Physical(pos) => self.0.setPositionPhysical(pos.0).await?,
|
||||
Position::Logical(pos) => self.0.setPositionLogical(pos.0).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setFullscreen(fullscreen).await?)
|
||||
}
|
||||
|
||||
pub async fn set_focus(&self) -> crate::Result<()> {
|
||||
Ok(self.0.setFocus().await?)
|
||||
}
|
||||
|
||||
pub async fn set_icon(&self, icon: &[u8]) -> crate::Result<()> {
|
||||
Ok(self.0.setIcon(icon).await?)
|
||||
}
|
||||
|
||||
pub async fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setSkipTaskbar(skip).await?)
|
||||
}
|
||||
|
||||
pub async fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setCursorGrab(grab).await?)
|
||||
}
|
||||
|
||||
pub async fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setCursorVisible(visible).await?)
|
||||
}
|
||||
|
||||
pub async fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> {
|
||||
Ok(self.0.setCursorIcon(&icon.to_string()).await?)
|
||||
}
|
||||
|
||||
pub async fn set_cursor_position(&self, position: Position) -> crate::Result<()> {
|
||||
match position {
|
||||
Position::Physical(pos) => self.0.setCursorPositionPhysical(pos.0).await?,
|
||||
Position::Logical(pos) => self.0.setCursorPositionLogical(pos.0).await?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> {
|
||||
Ok(self.0.setIgnoreCursorEvents(ignore).await?)
|
||||
}
|
||||
|
||||
pub async fn start_dragging(&self) -> crate::Result<()> {
|
||||
Ok(self.0.startDragging().await?)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn emit<T: Serialize>(&self, event: &str, payload: &T) -> crate::Result<()> {
|
||||
self.0
|
||||
.emit(event, serde_wasm_bindgen::to_value(payload).unwrap())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn listen<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
H: FnMut(Event<T>) + 'static,
|
||||
{
|
||||
let closure = Closure::<dyn FnMut(JsValue)>::new(move |raw| {
|
||||
(handler)(serde_wasm_bindgen::from_value(raw).unwrap())
|
||||
});
|
||||
|
||||
let unlisten = self.0.listen(event, &closure).await?;
|
||||
|
||||
closure.forget();
|
||||
|
||||
let unlisten = js_sys::Function::from(unlisten);
|
||||
Ok(move || {
|
||||
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn once<T, H>(&self, event: &str, mut handler: H) -> crate::Result<impl FnOnce()>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
H: FnMut(Event<T>) + 'static,
|
||||
{
|
||||
let closure = Closure::<dyn FnMut(JsValue)>::new(move |raw| {
|
||||
(handler)(serde_wasm_bindgen::from_value(raw).unwrap())
|
||||
});
|
||||
|
||||
let unlisten = self.0.once(event, &closure).await?;
|
||||
|
||||
closure.forget();
|
||||
|
||||
let unlisten = js_sys::Function::from(unlisten);
|
||||
Ok(move || {
|
||||
unlisten.call0(&wasm_bindgen::JsValue::NULL).unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct LogicalPosition(inner::LogicalPosition);
|
||||
|
||||
impl LogicalPosition {
|
||||
pub fn new(x: u32, y: u32) -> Self {
|
||||
Self(inner::LogicalPosition::new(x, y))
|
||||
}
|
||||
|
||||
pub fn x(&self) -> u32 {
|
||||
self.0.x()
|
||||
}
|
||||
pub fn set_x(&self, x: u32) {
|
||||
self.0.set_x(x)
|
||||
}
|
||||
pub fn y(&self) -> u32 {
|
||||
self.0.y()
|
||||
}
|
||||
pub fn set_y(&self, y: u32) {
|
||||
self.0.set_y(y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct PhysicalPosition(inner::PhysicalPosition);
|
||||
|
||||
impl PhysicalPosition {
|
||||
pub fn new(x: u32, y: u32) -> Self {
|
||||
Self(inner::PhysicalPosition::new(x, y))
|
||||
}
|
||||
|
||||
pub fn to_logical(self, scale_factor: u32) -> LogicalPosition {
|
||||
LogicalPosition(self.0.toLogical(scale_factor))
|
||||
}
|
||||
|
||||
pub fn x(&self) -> u32 {
|
||||
self.0.x()
|
||||
}
|
||||
pub fn set_x(&self, x: u32) {
|
||||
self.0.set_x(x)
|
||||
}
|
||||
pub fn y(&self) -> u32 {
|
||||
self.0.y()
|
||||
}
|
||||
pub fn set_y(&self, y: u32) {
|
||||
self.0.set_y(y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct LogicalSize(inner::LogicalSize);
|
||||
|
||||
impl LogicalSize {
|
||||
pub fn new(x: u32, y: u32) -> Self {
|
||||
Self(inner::LogicalSize::new(x, y))
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.0.width()
|
||||
}
|
||||
pub fn set_width(&self, x: u32) {
|
||||
self.0.set_width(x)
|
||||
}
|
||||
pub fn height(&self) -> u32 {
|
||||
self.0.height()
|
||||
}
|
||||
pub fn set_height(&self, y: u32) {
|
||||
self.0.set_height(y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct PhysicalSize(inner::PhysicalSize);
|
||||
|
||||
impl PhysicalSize {
|
||||
pub fn new(x: u32, y: u32) -> Self {
|
||||
Self(inner::PhysicalSize::new(x, y))
|
||||
}
|
||||
|
||||
pub fn to_logical(self, scale_factor: u32) -> LogicalSize {
|
||||
LogicalSize(self.0.toLogical(scale_factor))
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.0.width()
|
||||
}
|
||||
pub fn set_width(&self, x: u32) {
|
||||
self.0.set_width(x)
|
||||
}
|
||||
pub fn height(&self) -> u32 {
|
||||
self.0.height()
|
||||
}
|
||||
pub fn set_height(&self, y: u32) {
|
||||
self.0.set_height(y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Monitor(JsValue);
|
||||
|
||||
impl Monitor {
|
||||
pub fn name(&self) -> Option<String> {
|
||||
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("name")).unwrap();
|
||||
|
||||
raw.as_string()
|
||||
}
|
||||
|
||||
pub fn size(&self) -> PhysicalSize {
|
||||
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("size")).unwrap();
|
||||
|
||||
PhysicalSize(raw.unchecked_into())
|
||||
}
|
||||
|
||||
pub fn position(&self) -> PhysicalPosition {
|
||||
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("position")).unwrap();
|
||||
|
||||
PhysicalPosition(raw.unchecked_into())
|
||||
}
|
||||
|
||||
pub fn scale_factor(&self) -> u32 {
|
||||
let raw = js_sys::Reflect::get(&self.0, &JsValue::from_str("size"))
|
||||
.unwrap()
|
||||
.as_f64()
|
||||
.unwrap();
|
||||
|
||||
raw as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_window() -> WebviewWindow {
|
||||
WebviewWindow(inner::getCurrent())
|
||||
}
|
||||
|
||||
pub fn all_windows() -> Vec<WebviewWindow> {
|
||||
inner::getAll().into_iter().map(WebviewWindow).collect()
|
||||
}
|
||||
|
||||
pub async fn current_monitor() -> Monitor {
|
||||
Monitor(inner::currentMonitor().await)
|
||||
}
|
||||
pub async fn primary_monitor() -> Monitor {
|
||||
Monitor(inner::primaryMonitor().await)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AvailableMonitors {
|
||||
idx: u32,
|
||||
array: js_sys::Array,
|
||||
}
|
||||
|
||||
impl Iterator for AvailableMonitors {
|
||||
type Item = Monitor;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let raw = self.array.get(self.idx);
|
||||
|
||||
if raw.is_undefined() {
|
||||
None
|
||||
} else {
|
||||
let monitor = Monitor(raw);
|
||||
self.idx += 1;
|
||||
|
||||
Some(monitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn available_monitors() -> AvailableMonitors {
|
||||
AvailableMonitors {
|
||||
idx: 0,
|
||||
array: inner::availableMonitors().await.unchecked_into(),
|
||||
}
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use wasm_bindgen::{
|
||||
prelude::{wasm_bindgen, Closure},
|
||||
JsValue,
|
||||
};
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type LogicalPosition;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(x: u32, y: u32) -> LogicalPosition;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn x(this: &LogicalPosition) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_x(this: &LogicalPosition, x: u32);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn y(this: &LogicalPosition) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_y(this: &LogicalPosition, y: u32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type PhysicalPosition;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(x: u32, y: u32) -> PhysicalPosition;
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn toLogical(this: &PhysicalPosition, scaleFactor: u32) -> LogicalPosition;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn x(this: &PhysicalPosition) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_x(this: &PhysicalPosition, x: u32);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn y(this: &PhysicalPosition) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_y(this: &PhysicalPosition, y: u32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type LogicalSize;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(width: u32, height: u32) -> LogicalSize;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn width(this: &LogicalSize) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_width(this: &LogicalSize, width: u32);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn height(this: &LogicalSize) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_height(this: &LogicalSize, height: u32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type PhysicalSize;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(width: u32, height: u32) -> PhysicalSize;
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn toLogical(this: &PhysicalSize, scaleFactor: u32) -> LogicalSize;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn width(this: &PhysicalSize) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_width(this: &PhysicalSize, width: u32);
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn height(this: &PhysicalSize) -> u32;
|
||||
#[wasm_bindgen(method, setter)]
|
||||
pub fn set_height(this: &PhysicalSize, height: u32);
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type WebviewWindowHandle;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(label: &str) -> WebviewWindowHandle;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn listen(
|
||||
this: &WebviewWindowHandle,
|
||||
event: &str,
|
||||
handler: &Closure<dyn FnMut(JsValue)>,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn once(
|
||||
this: &WebviewWindowHandle,
|
||||
event: &str,
|
||||
handler: &Closure<dyn FnMut(JsValue)>,
|
||||
) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn emit(
|
||||
this: &WebviewWindowHandle,
|
||||
event: &str,
|
||||
payload: JsValue,
|
||||
) -> Result<(), JsValue>;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = WebviewWindowHandle)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type WindowManager;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(label: &str) -> WindowManager;
|
||||
#[wasm_bindgen(method, getter)]
|
||||
pub fn label(this: &WindowManager) -> String;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn scaleFactor(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn innerPosition(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn outerPosition(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn innerSize(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn outerSize(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn isFullscreen(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn isMaximized(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn isDecorated(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn isResizable(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn isVisible(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn theme(this: &WindowManager) -> Result<JsValue, JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn center(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn requestUserAttention(
|
||||
this: &WindowManager,
|
||||
requestType: u32,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setResizable(this: &WindowManager, resizable: bool) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setTitle(this: &WindowManager, title: &str) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn maximize(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn unmaximize(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn toggleMaximize(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn minimize(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn unminimize(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn show(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn hide(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn close(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setDecorations(this: &WindowManager, decorations: bool)
|
||||
-> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setAlwaysOnTop(this: &WindowManager, alwaysOnTop: bool)
|
||||
-> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setSize, catch)]
|
||||
pub async fn setSizePhysical(
|
||||
this: &WindowManager,
|
||||
size: PhysicalSize,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setSize, catch)]
|
||||
pub async fn setSizeLogical(this: &WindowManager, size: LogicalSize)
|
||||
-> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setMinSize, catch)]
|
||||
pub async fn setMinSizePhysical(
|
||||
this: &WindowManager,
|
||||
size: Option<PhysicalSize>,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setMinSize, catch)]
|
||||
pub async fn setMinSizeLogical(
|
||||
this: &WindowManager,
|
||||
size: Option<LogicalSize>,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setMaxSize, catch)]
|
||||
pub async fn setMaxSizePhysical(
|
||||
this: &WindowManager,
|
||||
size: Option<PhysicalSize>,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setMinSize, catch)]
|
||||
pub async fn setMaxSizeLogical(
|
||||
this: &WindowManager,
|
||||
size: Option<LogicalSize>,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setPosition, catch)]
|
||||
pub async fn setPositionPhysical(
|
||||
this: &WindowManager,
|
||||
position: PhysicalPosition,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setPosition, catch)]
|
||||
pub async fn setPositionLogical(
|
||||
this: &WindowManager,
|
||||
position: LogicalPosition,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setFullscreen(this: &WindowManager, fullscreen: bool) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setFocus(this: &WindowManager) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setIcon(this: &WindowManager, icon: &[u8]) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setSkipTaskbar(this: &WindowManager, skip: bool) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setCursorGrab(this: &WindowManager, grab: bool) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setCursorVisible(this: &WindowManager, visible: bool) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setCursorIcon(this: &WindowManager, icon: &str) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setCursorPosition, catch)]
|
||||
pub async fn setCursorPositionPhysical(
|
||||
this: &WindowManager,
|
||||
position: PhysicalPosition,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, js_name = setCursorPosition, catch)]
|
||||
pub async fn setCursorPositionLogical(
|
||||
this: &WindowManager,
|
||||
position: LogicalPosition,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn setIgnoreCursorEvents(
|
||||
this: &WindowManager,
|
||||
ignore: bool,
|
||||
) -> Result<(), JsValue>;
|
||||
#[wasm_bindgen(method, catch)]
|
||||
pub async fn startDragging(this: &WindowManager) -> Result<(), JsValue>;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(extends = WindowManager)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub type WebviewWindow;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(label: &str, options: ()) -> WebviewWindow;
|
||||
#[wasm_bindgen(static_method_of = WebviewWindow)]
|
||||
pub fn getByLabel(label: &str) -> Option<WebviewWindow>;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(module = "/src/window.js")]
|
||||
extern "C" {
|
||||
pub fn getCurrent() -> WebviewWindow;
|
||||
pub fn getAll() -> Vec<WebviewWindow>;
|
||||
pub async fn currentMonitor() -> JsValue;
|
||||
pub async fn primaryMonitor() -> JsValue;
|
||||
pub async fn availableMonitors() -> JsValue;
|
||||
}
|
||||
}
|
2
tauri
|
@ -1 +1 @@
|
|||
Subproject commit 35264b4c1801b381e0b867c1c35540f0fbb43365
|
||||
Subproject commit 2e1bd04775c0f05f1c0b67605e6abec4465dbf84
|