Merge remote-tracking branch 'upstream/main' into updater

This commit is contained in:
Max Coppen 2022-11-15 19:07:41 +01:00
commit 8b9299ec1c
87 changed files with 15088 additions and 667 deletions

91
src/app.js Normal file
View 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
};

View file

@ -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
View 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
View 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
};

View file

@ -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
View 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
View 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
View 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
};

View file

@ -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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

View file

@ -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
View 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
};

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
};

View file

@ -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
View 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

File diff suppressed because it is too large Load diff

825
src/window.rs Normal file
View 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;
}
}