Merge remote-tracking branch 'upstream/main' into updater
This commit is contained in:
commit
8b9299ec1c
87 changed files with 15088 additions and 667 deletions
91
src/app.js
Normal file
91
src/app.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
// 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/app.ts
|
||||
async function getVersion() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "App",
|
||||
message: {
|
||||
cmd: "getAppVersion"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function getName() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "App",
|
||||
message: {
|
||||
cmd: "getAppName"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function getTauriVersion() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "App",
|
||||
message: {
|
||||
cmd: "getTauriVersion"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function show() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "App",
|
||||
message: {
|
||||
cmd: "show"
|
||||
}
|
||||
});
|
||||
}
|
||||
async function hide() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "App",
|
||||
message: {
|
||||
cmd: "hide"
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
getName,
|
||||
getTauriVersion,
|
||||
getVersion,
|
||||
hide,
|
||||
show
|
||||
};
|
43
src/app.rs
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
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
|
||||
};
|
66
src/clipboard.js
Normal file
66
src/clipboard.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
// 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/clipboard.ts
|
||||
async function writeText(text) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Clipboard",
|
||||
message: {
|
||||
cmd: "writeText",
|
||||
data: text
|
||||
}
|
||||
});
|
||||
}
|
||||
async function readText() {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Clipboard",
|
||||
message: {
|
||||
cmd: "readText",
|
||||
data: null
|
||||
}
|
||||
});
|
||||
}
|
||||
export {
|
||||
readText,
|
||||
writeText
|
||||
};
|
|
@ -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
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
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>;
|
||||
}
|
||||
}
|
123
src/event.js
Normal file
123
src/event.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once3 = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once3) {
|
||||
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/helpers/event.ts
|
||||
async function _unlisten(event, eventId) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "unlisten",
|
||||
event,
|
||||
eventId
|
||||
}
|
||||
});
|
||||
}
|
||||
async function emit(event, windowLabel, payload) {
|
||||
await invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "emit",
|
||||
event,
|
||||
windowLabel,
|
||||
payload
|
||||
}
|
||||
});
|
||||
}
|
||||
async function listen(event, windowLabel, handler) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "listen",
|
||||
event,
|
||||
windowLabel,
|
||||
handler: transformCallback(handler)
|
||||
}
|
||||
}).then((eventId) => {
|
||||
return async () => _unlisten(event, eventId);
|
||||
});
|
||||
}
|
||||
async function once(event, windowLabel, handler) {
|
||||
return listen(event, windowLabel, (eventData) => {
|
||||
handler(eventData);
|
||||
_unlisten(event, eventData.id).catch(() => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/event.ts
|
||||
var TauriEvent = /* @__PURE__ */ ((TauriEvent2) => {
|
||||
TauriEvent2["WINDOW_RESIZED"] = "tauri://resize";
|
||||
TauriEvent2["WINDOW_MOVED"] = "tauri://move";
|
||||
TauriEvent2["WINDOW_CLOSE_REQUESTED"] = "tauri://close-requested";
|
||||
TauriEvent2["WINDOW_CREATED"] = "tauri://window-created";
|
||||
TauriEvent2["WINDOW_DESTROYED"] = "tauri://destroyed";
|
||||
TauriEvent2["WINDOW_FOCUS"] = "tauri://focus";
|
||||
TauriEvent2["WINDOW_BLUR"] = "tauri://blur";
|
||||
TauriEvent2["WINDOW_SCALE_FACTOR_CHANGED"] = "tauri://scale-change";
|
||||
TauriEvent2["WINDOW_THEME_CHANGED"] = "tauri://theme-changed";
|
||||
TauriEvent2["WINDOW_FILE_DROP"] = "tauri://file-drop";
|
||||
TauriEvent2["WINDOW_FILE_DROP_HOVER"] = "tauri://file-drop-hover";
|
||||
TauriEvent2["WINDOW_FILE_DROP_CANCELLED"] = "tauri://file-drop-cancelled";
|
||||
TauriEvent2["MENU"] = "tauri://menu";
|
||||
TauriEvent2["CHECK_UPDATE"] = "tauri://update";
|
||||
TauriEvent2["UPDATE_AVAILABLE"] = "tauri://update-available";
|
||||
TauriEvent2["INSTALL_UPDATE"] = "tauri://update-install";
|
||||
TauriEvent2["STATUS_UPDATE"] = "tauri://update-status";
|
||||
TauriEvent2["DOWNLOAD_PROGRESS"] = "tauri://update-download-progress";
|
||||
return TauriEvent2;
|
||||
})(TauriEvent || {});
|
||||
async function listen2(event, handler) {
|
||||
return listen(event, null, handler);
|
||||
}
|
||||
async function once2(event, handler) {
|
||||
return once(event, null, handler);
|
||||
}
|
||||
async function emit2(event, payload) {
|
||||
return emit(event, void 0, payload);
|
||||
}
|
||||
export {
|
||||
TauriEvent,
|
||||
emit2 as emit,
|
||||
listen2 as listen,
|
||||
once2 as once
|
||||
};
|
42
src/event.rs
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
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
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
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
2414
src/index.js
Normal file
File diff suppressed because it is too large
Load diff
36
src/lib.rs
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>;
|
||||
|
|
30
src/mocks.js
Normal file
30
src/mocks.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// tauri/tooling/api/src/mocks.ts
|
||||
function mockIPC(cb) {
|
||||
window.__TAURI_IPC__ = async ({
|
||||
cmd,
|
||||
callback,
|
||||
error,
|
||||
...args
|
||||
}) => {
|
||||
try {
|
||||
window[`_${callback}`](await cb(cmd, args));
|
||||
} catch (err) {
|
||||
window[`_${error}`](err);
|
||||
}
|
||||
};
|
||||
}
|
||||
function mockWindows(current, ...additionalWindows) {
|
||||
window.__TAURI_METADATA__ = {
|
||||
__windows: [current, ...additionalWindows].map((label) => ({ label })),
|
||||
__currentWindow: { label: current }
|
||||
};
|
||||
}
|
||||
function clearMocks() {
|
||||
delete window.__TAURI_IPC__;
|
||||
delete window.__TAURI_METADATA__;
|
||||
}
|
||||
export {
|
||||
clearMocks,
|
||||
mockIPC,
|
||||
mockWindows
|
||||
};
|
|
@ -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
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
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
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
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
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
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
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
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
|
||||
};
|
46
src/tauri.js
Normal file
46
src/tauri.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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
|
||||
});
|
||||
});
|
||||
}
|
||||
function convertFileSrc(filePath, protocol = "asset") {
|
||||
const path = encodeURIComponent(filePath);
|
||||
return navigator.userAgent.includes("Windows") ? `https://${protocol}.localhost/${path}` : `${protocol}://localhost/${path}`;
|
||||
}
|
||||
export {
|
||||
convertFileSrc,
|
||||
invoke,
|
||||
transformCallback
|
||||
};
|
42
src/tauri.rs
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>;
|
||||
}
|
||||
}
|
||||
|
|
185
src/updater.js
Normal file
185
src/updater.js
Normal file
|
@ -0,0 +1,185 @@
|
|||
// tauri/tooling/api/src/tauri.ts
|
||||
function uid() {
|
||||
return window.crypto.getRandomValues(new Uint32Array(1))[0];
|
||||
}
|
||||
function transformCallback(callback, once3 = false) {
|
||||
const identifier = uid();
|
||||
const prop = `_${identifier}`;
|
||||
Object.defineProperty(window, prop, {
|
||||
value: (result) => {
|
||||
if (once3) {
|
||||
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/helpers/event.ts
|
||||
async function _unlisten(event, eventId) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "unlisten",
|
||||
event,
|
||||
eventId
|
||||
}
|
||||
});
|
||||
}
|
||||
async function emit(event, windowLabel, payload) {
|
||||
await invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "emit",
|
||||
event,
|
||||
windowLabel,
|
||||
payload
|
||||
}
|
||||
});
|
||||
}
|
||||
async function listen(event, windowLabel, handler) {
|
||||
return invokeTauriCommand({
|
||||
__tauriModule: "Event",
|
||||
message: {
|
||||
cmd: "listen",
|
||||
event,
|
||||
windowLabel,
|
||||
handler: transformCallback(handler)
|
||||
}
|
||||
}).then((eventId) => {
|
||||
return async () => _unlisten(event, eventId);
|
||||
});
|
||||
}
|
||||
async function once(event, windowLabel, handler) {
|
||||
return listen(event, windowLabel, (eventData) => {
|
||||
handler(eventData);
|
||||
_unlisten(event, eventData.id).catch(() => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/event.ts
|
||||
async function listen2(event, handler) {
|
||||
return listen(event, null, handler);
|
||||
}
|
||||
async function once2(event, handler) {
|
||||
return once(event, null, handler);
|
||||
}
|
||||
async function emit2(event, payload) {
|
||||
return emit(event, void 0, payload);
|
||||
}
|
||||
|
||||
// tauri/tooling/api/src/updater.ts
|
||||
async function onUpdaterEvent(handler) {
|
||||
return listen2("tauri://update-status" /* STATUS_UPDATE */, (data) => {
|
||||
handler(data?.payload);
|
||||
});
|
||||
}
|
||||
async function installUpdate() {
|
||||
let unlistenerFn;
|
||||
function cleanListener() {
|
||||
if (unlistenerFn) {
|
||||
unlistenerFn();
|
||||
}
|
||||
unlistenerFn = void 0;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function onStatusChange(statusResult) {
|
||||
if (statusResult.error) {
|
||||
cleanListener();
|
||||
return reject(statusResult.error);
|
||||
}
|
||||
if (statusResult.status === "DONE") {
|
||||
cleanListener();
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
onUpdaterEvent(onStatusChange).then((fn) => {
|
||||
unlistenerFn = fn;
|
||||
}).catch((e) => {
|
||||
cleanListener();
|
||||
throw e;
|
||||
});
|
||||
emit2("tauri://update-install" /* INSTALL_UPDATE */).catch((e) => {
|
||||
cleanListener();
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
}
|
||||
async function checkUpdate() {
|
||||
let unlistenerFn;
|
||||
function cleanListener() {
|
||||
if (unlistenerFn) {
|
||||
unlistenerFn();
|
||||
}
|
||||
unlistenerFn = void 0;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function onUpdateAvailable(manifest) {
|
||||
cleanListener();
|
||||
return resolve({
|
||||
manifest,
|
||||
shouldUpdate: true
|
||||
});
|
||||
}
|
||||
function onStatusChange(statusResult) {
|
||||
if (statusResult.error) {
|
||||
cleanListener();
|
||||
return reject(statusResult.error);
|
||||
}
|
||||
if (statusResult.status === "UPTODATE") {
|
||||
cleanListener();
|
||||
return resolve({
|
||||
shouldUpdate: false
|
||||
});
|
||||
}
|
||||
}
|
||||
once2("tauri://update-available" /* UPDATE_AVAILABLE */, (data) => {
|
||||
onUpdateAvailable(data?.payload);
|
||||
}).catch((e) => {
|
||||
cleanListener();
|
||||
throw e;
|
||||
});
|
||||
onUpdaterEvent(onStatusChange).then((fn) => {
|
||||
unlistenerFn = fn;
|
||||
}).catch((e) => {
|
||||
cleanListener();
|
||||
throw e;
|
||||
});
|
||||
emit2("tauri://update" /* CHECK_UPDATE */).catch((e) => {
|
||||
cleanListener();
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
}
|
||||
export {
|
||||
checkUpdate,
|
||||
installUpdate,
|
||||
onUpdaterEvent
|
||||
};
|
1004
src/window.js
Normal file
1004
src/window.js
Normal file
File diff suppressed because it is too large
Load diff
825
src/window.rs
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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue