mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-04-29 12:06:01 +02:00
Merge remote-tracking branch 'origin/v2' into plugin/secure-storage
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"deep-link": patch
|
||||
"deep-link-js": patch
|
||||
---
|
||||
|
||||
Fix Exec= field in desktop handler if executable path changes
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"fs": patch
|
||||
"fs-js": patch
|
||||
---
|
||||
|
||||
Enhance error messages.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
geolocation: patch
|
||||
geolocation-js: patch
|
||||
---
|
||||
|
||||
On Android, use the `timeout` value for `setMinUpdateIntervalMillis`, `setMaxUpdateDelayMillis` and `setIntervalMillis` instead of just `minUpdateInterval`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
nfc: patch
|
||||
nfc-js: patch
|
||||
---
|
||||
|
||||
On iOS, the reader session will now get closed properly on errors, preventing dangling invalid sessions that could prevent subsequent write attempts.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"opener": patch
|
||||
"opener-js": patch
|
||||
---
|
||||
|
||||
Fix opener doesn't open same origin links in the browser
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
store: minor
|
||||
store-js: minor
|
||||
---
|
||||
|
||||
Allow setting defaults from the JavaScript API
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
store: minor
|
||||
store-js: minor
|
||||
---
|
||||
|
||||
Add an new option `overrideDefaults` for creating/loading and reloading the store that overrides the store with the on-disk state, ignoring defaults
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"updater": minor
|
||||
"updater-js": minor
|
||||
---
|
||||
|
||||
Updater plugin now supports all bundle types: Deb, Rpm and AppImage for Linux; NSiS, MSI for Windows.
|
||||
+1
-1
@@ -58,4 +58,4 @@ pids
|
||||
.idea
|
||||
debug.log
|
||||
TODO.md
|
||||
.aider*
|
||||
.aider.*
|
||||
|
||||
Generated
+137
-69
@@ -220,7 +220,7 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "api"
|
||||
version = "2.0.32"
|
||||
version = "2.0.36"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -903,7 +903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
"toml 0.8.20",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1608,9 +1608,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dlopen2"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6"
|
||||
checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
|
||||
dependencies = [
|
||||
"dlopen2_derive",
|
||||
"libc",
|
||||
@@ -1770,7 +1770,7 @@ dependencies = [
|
||||
"cc",
|
||||
"memchr",
|
||||
"rustc_version",
|
||||
"toml",
|
||||
"toml 0.8.20",
|
||||
"vswhom",
|
||||
"winreg 0.52.0",
|
||||
]
|
||||
@@ -3648,9 +3648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.16.1"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492"
|
||||
checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
@@ -3664,7 +3664,7 @@ dependencies = [
|
||||
"png",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4140,6 +4140,17 @@ dependencies = [
|
||||
"objc2-foundation 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-security"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3126341c65c5d5728423ae95d788e1b660756486ad0592307ab87ba02d9a7268"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"objc2 0.6.0",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-ui-kit"
|
||||
version = "0.3.0"
|
||||
@@ -4164,6 +4175,7 @@ dependencies = [
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-security",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5668,6 +5680,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -5712,9 +5733,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
|
||||
checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5723,13 +5744,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript-impl"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
|
||||
checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6364,17 +6385,18 @@ dependencies = [
|
||||
"cfg-expr",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"toml 0.8.20",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.34.0"
|
||||
version = "0.34.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
|
||||
checksum = "4daa814018fecdfb977b59a094df4bd43b42e8e21f88fddfc05807e6f46efaaf"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"block2 0.6.0",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics",
|
||||
"crossbeam-channel",
|
||||
@@ -6443,16 +6465,17 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.6.0"
|
||||
version = "2.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f7a0f4019c80391d143ee26cd7cd1ed271ac241d3087d333f99f3269ba90812"
|
||||
checksum = "5d545ccf7b60dcd44e07c6fb5aeb09140966f0aabd5d2aa14a6821df7bc99348"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"cookie",
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
"embed_plist",
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.3.2",
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.5.0",
|
||||
@@ -6468,6 +6491,7 @@ dependencies = [
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
@@ -6497,9 +6521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
|
||||
checksum = "67945dbaf8920dbe3a1e56721a419a0c3d085254ab24cff5b9ad55e2b0016e0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@@ -6515,15 +6539,15 @@ dependencies = [
|
||||
"tauri-codegen",
|
||||
"tauri-utils",
|
||||
"tauri-winres",
|
||||
"toml",
|
||||
"toml 0.9.5",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
|
||||
checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"ico",
|
||||
@@ -6547,9 +6571,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f59e1d1fa9651212dcb890a0c66226d819b716490b0cf43c078514da3591705"
|
||||
checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -6561,9 +6585,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3"
|
||||
checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@@ -6572,7 +6596,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils",
|
||||
"toml",
|
||||
"toml 0.9.5",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -6641,9 +6665,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-deep-link"
|
||||
version = "2.4.1"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"plist",
|
||||
"rust-ini",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6659,7 +6684,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
@@ -6675,7 +6700,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.4.1"
|
||||
version = "2.4.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
@@ -6691,7 +6716,7 @@ dependencies = [
|
||||
"tauri-plugin",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.12",
|
||||
"toml",
|
||||
"toml 0.9.5",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -6736,7 +6761,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.5.1"
|
||||
version = "2.5.2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cookie_store",
|
||||
@@ -6772,7 +6797,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"byte-unit",
|
||||
@@ -6793,7 +6818,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-nfc"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -6806,7 +6831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-notification"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"color-backtrace",
|
||||
"ctor",
|
||||
@@ -6828,7 +6853,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
@@ -6848,7 +6873,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"gethostname 1.0.1",
|
||||
"log",
|
||||
@@ -6864,7 +6889,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-persisted-scope"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bincode",
|
||||
@@ -6916,7 +6941,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"log",
|
||||
@@ -6935,7 +6960,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-single-instance"
|
||||
version = "2.3.2"
|
||||
version = "2.3.4"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -6967,7 +6992,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-store"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"serde",
|
||||
@@ -7080,9 +7105,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.7.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
|
||||
checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
@@ -7091,20 +7116,23 @@ dependencies = [
|
||||
"jni",
|
||||
"objc2 0.6.0",
|
||||
"objc2-ui-kit",
|
||||
"objc2-web-kit",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"windows 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.7.0"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe52ed0ef40fd7ad51a620ecb3018e32eba3040bb95025216a962a37f6f050c5"
|
||||
checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
@@ -7129,16 +7157,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.5.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
|
||||
checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"ctor",
|
||||
"dunce",
|
||||
"getrandom 0.2.15",
|
||||
"getrandom 0.3.2",
|
||||
"glob",
|
||||
"html5ever",
|
||||
"http",
|
||||
@@ -7160,7 +7188,7 @@ dependencies = [
|
||||
"serialize-to-javascript",
|
||||
"swift-rs",
|
||||
"thiserror 2.0.12",
|
||||
"toml",
|
||||
"toml 0.9.5",
|
||||
"url",
|
||||
"urlpattern",
|
||||
"uuid",
|
||||
@@ -7174,7 +7202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0"
|
||||
dependencies = [
|
||||
"embed-resource",
|
||||
"toml",
|
||||
"toml 0.8.20",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7476,11 +7504,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"serde_spanned 0.6.8",
|
||||
"toml_datetime 0.6.8",
|
||||
"toml_edit 0.22.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_spanned 1.0.0",
|
||||
"toml_datetime 0.7.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 0.7.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
@@ -7490,6 +7533,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
@@ -7497,7 +7549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"toml_datetime",
|
||||
"toml_datetime 0.6.8",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
@@ -7508,7 +7560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"toml_datetime",
|
||||
"toml_datetime 0.6.8",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
@@ -7520,11 +7572,26 @@ checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow 0.7.6",
|
||||
"serde_spanned 0.6.8",
|
||||
"toml_datetime 0.6.8",
|
||||
"winnow 0.7.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||
dependencies = [
|
||||
"winnow 0.7.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.2"
|
||||
@@ -7586,9 +7653,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.20.0"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5"
|
||||
checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dirs 6.0.0",
|
||||
@@ -8833,9 +8900,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.6"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
||||
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -8901,14 +8968,15 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.52.0"
|
||||
version = "0.53.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b08db04817a654a7e3339647d9cf8b497ed9ddcd4ec7cfda5a3a220c10a3bba3"
|
||||
checksum = "e3b6763512fe4b51c80b3ce9b50939d682acb4de335dfabbdb20d7a2642199b7"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.0",
|
||||
"cookie",
|
||||
"crossbeam-channel",
|
||||
"dirs 6.0.0",
|
||||
"dpi",
|
||||
"dunce",
|
||||
"gdkx11",
|
||||
@@ -9069,7 +9137,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"windows-sys 0.60.2",
|
||||
"winnow 0.7.6",
|
||||
"winnow 0.7.12",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
@@ -9108,7 +9176,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"winnow 0.7.6",
|
||||
"winnow 0.7.12",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
@@ -9295,7 +9363,7 @@ dependencies = [
|
||||
"enumflags2",
|
||||
"serde",
|
||||
"url",
|
||||
"winnow 0.7.6",
|
||||
"winnow 0.7.12",
|
||||
"zvariant_derive",
|
||||
"zvariant_utils",
|
||||
]
|
||||
@@ -9324,5 +9392,5 @@ dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"syn 2.0.100",
|
||||
"winnow 0.7.6",
|
||||
"winnow 0.7.12",
|
||||
]
|
||||
|
||||
+4
-4
@@ -12,10 +12,10 @@ resolver = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
log = "0.4"
|
||||
tauri = { version = "2.6", default-features = false }
|
||||
tauri-build = "2.3"
|
||||
tauri-plugin = "2.3"
|
||||
tauri-utils = "2.5"
|
||||
tauri = { version = "2.8.2", default-features = false }
|
||||
tauri-build = "2.4"
|
||||
tauri-plugin = "2.4"
|
||||
tauri-utils = "2.7"
|
||||
serde_json = "1"
|
||||
thiserror = "2"
|
||||
url = "2"
|
||||
|
||||
+2
-1
@@ -3,11 +3,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import eslint from '@eslint/js'
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import eslintConfigPrettier from 'eslint-config-prettier'
|
||||
import eslintPluginSecurity from 'eslint-plugin-security'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
export default defineConfig(
|
||||
{
|
||||
ignores: [
|
||||
'**/target',
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.32]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog-js@2.4.0`
|
||||
- Upgraded to `log-js@2.7.0`
|
||||
|
||||
## \[2.0.31]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `shell-js@2.3.1`
|
||||
|
||||
## \[2.0.30]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `notification-js@2.3.1`
|
||||
|
||||
## \[2.0.29]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.2`
|
||||
- Upgraded to `nfc-js@2.3.1`
|
||||
- Upgraded to `opener-js@2.5.0`
|
||||
- Upgraded to `os-js@2.3.1`
|
||||
- Upgraded to `store-js@2.4.0`
|
||||
- Upgraded to `dialog-js@2.3.3`
|
||||
- Upgraded to `http-js@2.5.2`
|
||||
|
||||
## \[2.0.28]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=0"
|
||||
/>
|
||||
<title>Svelte + Vite App</title>
|
||||
</head>
|
||||
|
||||
+13
-13
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "api",
|
||||
"private": true,
|
||||
"version": "2.0.28",
|
||||
"version": "2.0.32",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false",
|
||||
@@ -10,25 +10,25 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.7.0",
|
||||
"@tauri-apps/api": "2.8.0",
|
||||
"@tauri-apps/plugin-barcode-scanner": "^2.4.0",
|
||||
"@tauri-apps/plugin-biometric": "^2.3.0",
|
||||
"@tauri-apps/plugin-cli": "^2.4.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.3.2",
|
||||
"@tauri-apps/plugin-fs": "^2.4.1",
|
||||
"@tauri-apps/plugin-dialog": "^2.4.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.2",
|
||||
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
||||
"@tauri-apps/plugin-global-shortcut": "^2.3.0",
|
||||
"@tauri-apps/plugin-haptics": "^2.2.0",
|
||||
"@tauri-apps/plugin-http": "^2.5.1",
|
||||
"@tauri-apps/plugin-nfc": "^2.3.0",
|
||||
"@tauri-apps/plugin-notification": "^2.3.0",
|
||||
"@tauri-apps/plugin-opener": "^2.4.0",
|
||||
"@tauri-apps/plugin-os": "^2.3.0",
|
||||
"@tauri-apps/plugin-http": "^2.5.2",
|
||||
"@tauri-apps/plugin-nfc": "^2.3.1",
|
||||
"@tauri-apps/plugin-notification": "^2.3.1",
|
||||
"@tauri-apps/plugin-opener": "^2.5.0",
|
||||
"@tauri-apps/plugin-os": "^2.3.1",
|
||||
"@tauri-apps/plugin-process": "^2.3.0",
|
||||
"@tauri-apps/plugin-shell": "^2.3.0",
|
||||
"@tauri-apps/plugin-secure-storage": "file:../../plugins/secure-storage",
|
||||
"@tauri-apps/plugin-store": "^2.3.0",
|
||||
"@tauri-apps/plugin-shell": "^2.3.1",
|
||||
"@tauri-apps/plugin-store": "^2.4.0",
|
||||
"@tauri-apps/plugin-updater": "^2.9.0",
|
||||
"@tauri-apps/plugin-upload": "^2.3.0",
|
||||
"@zerodevx/svelte-json-view": "1.0.11"
|
||||
@@ -37,10 +37,10 @@
|
||||
"@iconify-json/codicon": "^1.2.12",
|
||||
"@iconify-json/ph": "^1.2.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
||||
"@tauri-apps/cli": "2.7.1",
|
||||
"@tauri-apps/cli": "2.8.4",
|
||||
"@unocss/extractor-svelte": "^66.3.3",
|
||||
"svelte": "^5.20.4",
|
||||
"unocss": "^66.3.3",
|
||||
"vite": "^7.0.4"
|
||||
"vite": "^7.0.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.36]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog@2.4.0`
|
||||
- Upgraded to `log@2.7.0`
|
||||
|
||||
## \[2.0.35]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `shell@2.3.1`
|
||||
|
||||
## \[2.0.34]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `notification@2.3.1`
|
||||
|
||||
## \[2.0.33]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs@2.4.2`
|
||||
- Upgraded to `nfc@2.3.1`
|
||||
- Upgraded to `opener@2.5.0`
|
||||
- Upgraded to `os@2.3.1`
|
||||
- Upgraded to `store@2.4.0`
|
||||
- Upgraded to `dialog@2.3.3`
|
||||
- Upgraded to `http@2.5.2`
|
||||
|
||||
## \[2.0.32]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "api"
|
||||
publish = false
|
||||
version = "2.0.32"
|
||||
version = "2.0.36"
|
||||
description = "An example Tauri Application showcasing the api"
|
||||
edition = "2021"
|
||||
rust-version = { workspace = true }
|
||||
@@ -20,25 +20,25 @@ serde = { workspace = true }
|
||||
tiny_http = "0.12"
|
||||
time = "0.3"
|
||||
log = { workspace = true }
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.6.0" }
|
||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.1", features = [
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.7.0" }
|
||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.2", features = [
|
||||
"watch",
|
||||
] }
|
||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.0" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.3.2" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.4.0" }
|
||||
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
||||
"multipart",
|
||||
"cookies",
|
||||
], version = "2.5.1" }
|
||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.0", features = [
|
||||
], version = "2.5.2" }
|
||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.1", features = [
|
||||
"windows7-compat",
|
||||
] }
|
||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.0" }
|
||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.1" }
|
||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.0" }
|
||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.4.0" }
|
||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.5.0" }
|
||||
tauri-plugin-secure-storage = { path = "../../../plugins/secure-storage" }
|
||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.0" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.3.0" }
|
||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.1" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.0" }
|
||||
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
|
||||
|
||||
[dependencies.tauri]
|
||||
@@ -63,7 +63,7 @@ tauri-plugin-window-state = { path = "../../../plugins/window-state", version =
|
||||
|
||||
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.0" }
|
||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.0" }
|
||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.1" }
|
||||
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.0" }
|
||||
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.0" }
|
||||
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.0" }
|
||||
|
||||
@@ -68,6 +68,9 @@
|
||||
"fs:allow-rename",
|
||||
"fs:allow-mkdir",
|
||||
"fs:allow-remove",
|
||||
"fs:allow-stat",
|
||||
"fs:allow-fstat",
|
||||
"fs:allow-lstat",
|
||||
"fs:allow-write-text-file",
|
||||
"fs:read-meta",
|
||||
"fs:scope-download-recursive",
|
||||
@@ -75,6 +78,9 @@
|
||||
{
|
||||
"identifier": "fs:scope-appdata-recursive",
|
||||
"allow": [
|
||||
{
|
||||
"path": "$APPDATA/db/"
|
||||
},
|
||||
{
|
||||
"path": "$APPDATA/db/**"
|
||||
}
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
await message("Tauri is awesome!");
|
||||
}
|
||||
|
||||
async function msgCustom(result) {
|
||||
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
|
||||
await message(`Tauri is: `, { buttons })
|
||||
.then((res) => onMessage(`Tauri is ${res}`))
|
||||
.catch(onMessage);
|
||||
}
|
||||
|
||||
function openDialog() {
|
||||
open({
|
||||
title: "My wonderful open dialog",
|
||||
@@ -136,12 +143,17 @@
|
||||
<label for="dialog-directory">Directory</label>
|
||||
</div>
|
||||
<br />
|
||||
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
||||
<button class="btn" id="save-dialog" on:click={saveDialog}
|
||||
>Open save dialog</button
|
||||
>
|
||||
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
|
||||
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
|
||||
>Prompt (custom)</button
|
||||
>
|
||||
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
|
||||
|
||||
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
|
||||
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
||||
<button class="btn" id="save-dialog" on:click={saveDialog}
|
||||
>Open save dialog</button
|
||||
>
|
||||
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
|
||||
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
|
||||
>Prompt (custom)</button
|
||||
>
|
||||
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
|
||||
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>
|
||||
|
||||
</div>
|
||||
@@ -1,194 +1,214 @@
|
||||
<script>
|
||||
import * as fs from "@tauri-apps/plugin-fs";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { arrayBufferToBase64 } from "../lib/utils";
|
||||
import { onDestroy } from "svelte";
|
||||
import * as fs from '@tauri-apps/plugin-fs'
|
||||
import * as os from '@tauri-apps/plugin-os'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { arrayBufferToBase64 } from '../lib/utils'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
export let onMessage;
|
||||
export let insecureRenderHtml;
|
||||
const { onMessage, insecureRenderHtml } = $props()
|
||||
|
||||
let path = "";
|
||||
let img;
|
||||
let path = $state('')
|
||||
let img
|
||||
/** @type {fs.FileHandle} */
|
||||
let file;
|
||||
let renameTo;
|
||||
let watchPath = "";
|
||||
let watchDebounceDelay = "0";
|
||||
let watchRecursive = false;
|
||||
let unwatchFn;
|
||||
let unwatchPath = "";
|
||||
let file = $state()
|
||||
let renameTo = $state()
|
||||
let watchPath = $state('')
|
||||
let watchDebounceDelay = $state(0)
|
||||
let watchRecursive = $state(false)
|
||||
/** @type {fs.BaseDirectory | undefined} */
|
||||
let baseDir = $state()
|
||||
let unwatchFn
|
||||
let unwatchPath = ''
|
||||
let isMobile = $state(false)
|
||||
|
||||
function getDir() {
|
||||
const dirSelect = document.getElementById("dir");
|
||||
return dirSelect.value ? parseInt(dir.value) : null;
|
||||
}
|
||||
onMount(() => {
|
||||
let platform = os.platform()
|
||||
isMobile = platform === 'android' || platform === 'ios'
|
||||
})
|
||||
|
||||
const DirOptions = Object.keys(fs.BaseDirectory)
|
||||
.filter((key) => isNaN(parseInt(key)))
|
||||
.map((dir) => [dir, fs.BaseDirectory[dir]]);
|
||||
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) =>
|
||||
isNaN(parseInt(key))
|
||||
)
|
||||
|
||||
function open() {
|
||||
fs.open(path, {
|
||||
baseDir: getDir(),
|
||||
baseDir,
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
create: true
|
||||
})
|
||||
.then((f) => {
|
||||
file = f;
|
||||
onMessage(`Opened ${path}`);
|
||||
file = f
|
||||
onMessage(`Opened ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function mkdir() {
|
||||
fs.mkdir(path, { baseDir: getDir() })
|
||||
fs.mkdir(path, { baseDir, recursive: true })
|
||||
.then(() => {
|
||||
onMessage(`Created dir ${path}`);
|
||||
onMessage(`Created dir ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function remove() {
|
||||
fs.remove(path, { baseDir: getDir() })
|
||||
fs.remove(path, { baseDir })
|
||||
.then(() => {
|
||||
onMessage(`Removed ${path}`);
|
||||
onMessage(`Removed ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function rename() {
|
||||
fs.rename(path, renameTo, {
|
||||
oldPathBaseDir: getDir(),
|
||||
newPathBaseDir: getDir(),
|
||||
oldPathBaseDir,
|
||||
newPathBaseDir
|
||||
})
|
||||
.then(() => {
|
||||
onMessage(`Renamed ${path} to ${renameTo}`);
|
||||
onMessage(`Renamed ${path} to ${renameTo}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function truncate() {
|
||||
file
|
||||
.truncate(0)
|
||||
.then(() => {
|
||||
onMessage(`Truncated file`);
|
||||
onMessage(`Truncated file`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function write() {
|
||||
const encoder = new TextEncoder()
|
||||
file
|
||||
.write(encoder.encode('Hello from Tauri :)'))
|
||||
.then(() => {
|
||||
onMessage(`wrote to file`)
|
||||
})
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function stat() {
|
||||
file
|
||||
.stat()
|
||||
.then((stat) => {
|
||||
onMessage(`File stat ${JSON.stringify(stat)}`);
|
||||
onMessage(`File stat ${JSON.stringify(stat)}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function read() {
|
||||
const opts = {
|
||||
baseDir: getDir(),
|
||||
};
|
||||
baseDir
|
||||
}
|
||||
fs.stat(path, opts)
|
||||
.then((stat) => {
|
||||
const isFile = stat.isFile;
|
||||
const isFile = stat.isFile
|
||||
|
||||
const promise = isFile
|
||||
? fs.readFile(path, opts)
|
||||
: fs.readDir(path, opts);
|
||||
: fs.readDir(path, opts)
|
||||
promise
|
||||
.then(function (response) {
|
||||
if (isFile) {
|
||||
if (path.includes(".png") || path.includes(".jpg")) {
|
||||
if (path.includes('.png') || path.includes('.jpg')) {
|
||||
arrayBufferToBase64(
|
||||
new Uint8Array(response),
|
||||
function (base64) {
|
||||
const src = "data:image/png;base64," + base64;
|
||||
insecureRenderHtml('<img src="' + src + '"></img>');
|
||||
const src = 'data:image/png;base64,' + base64
|
||||
insecureRenderHtml('<img src="' + src + '"></img>')
|
||||
}
|
||||
);
|
||||
)
|
||||
} else {
|
||||
const value = String.fromCharCode.apply(null, response);
|
||||
const value = String.fromCharCode.apply(null, response)
|
||||
insecureRenderHtml(
|
||||
'<textarea id="file-response"></textarea><button id="file-save">Save</button>'
|
||||
);
|
||||
)
|
||||
setTimeout(() => {
|
||||
const fileInput = document.getElementById("file-response");
|
||||
fileInput.value = value;
|
||||
const fileInput = document.getElementById('file-response')
|
||||
fileInput.value = value
|
||||
document
|
||||
.getElementById("file-save")
|
||||
.addEventListener("click", function () {
|
||||
.getElementById('file-save')
|
||||
.addEventListener('click', function () {
|
||||
fs.writeTextFile(path, fileInput.value, {
|
||||
baseDir: getDir(),
|
||||
}).catch(onMessage);
|
||||
});
|
||||
});
|
||||
baseDir
|
||||
}).catch(onMessage)
|
||||
})
|
||||
})
|
||||
}
|
||||
} else {
|
||||
onMessage(response);
|
||||
onMessage(response)
|
||||
}
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function setSrc() {
|
||||
img.src = convertFileSrc(path);
|
||||
img.src = convertFileSrc(path)
|
||||
}
|
||||
|
||||
function watch() {
|
||||
unwatch();
|
||||
unwatch()
|
||||
if (watchPath) {
|
||||
onMessage(`Watching ${watchPath} for changes`);
|
||||
onMessage(`Watching ${watchPath} for changes`)
|
||||
let options = {
|
||||
recursive: watchRecursive,
|
||||
delayMs: parseInt(watchDebounceDelay),
|
||||
};
|
||||
delayMs: watchDebounceDelay
|
||||
}
|
||||
if (options.delayMs === 0) {
|
||||
fs.watchImmediate(watchPath, onMessage, options)
|
||||
.then((fn) => {
|
||||
unwatchFn = fn;
|
||||
unwatchPath = watchPath;
|
||||
unwatchFn = fn
|
||||
unwatchPath = watchPath
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
} else {
|
||||
fs.watch(watchPath, onMessage, options)
|
||||
.then((fn) => {
|
||||
unwatchFn = fn;
|
||||
unwatchPath = watchPath;
|
||||
unwatchFn = fn
|
||||
unwatchPath = watchPath
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unwatch() {
|
||||
if (unwatchFn) {
|
||||
onMessage(`Stopped watching ${unwatchPath} for changes`);
|
||||
unwatchFn();
|
||||
onMessage(`Stopped watching ${unwatchPath} for changes`)
|
||||
unwatchFn()
|
||||
}
|
||||
unwatchFn = undefined;
|
||||
unwatchPath = undefined;
|
||||
unwatchFn = undefined
|
||||
unwatchPath = undefined
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (file) {
|
||||
file.close();
|
||||
file.close()
|
||||
}
|
||||
if (unwatchFn) {
|
||||
unwatchFn();
|
||||
unwatchFn()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
{#if isMobile}
|
||||
<div>
|
||||
On mobile, paths outside of App* paths require the use of dialogs
|
||||
regardless of Tauri's scope mechanism.
|
||||
</div>
|
||||
<br />
|
||||
{/if}
|
||||
<div class="flex gap-1">
|
||||
<select class="input" id="dir">
|
||||
<option value="">None</option>
|
||||
{#each DirOptions as dir}
|
||||
<option value={dir[1]}>{dir[0]}</option>
|
||||
<select class="input" bind:value={baseDir}>
|
||||
<option value={undefined} selected>None</option>
|
||||
{#each dirOptions as dir}
|
||||
<option value={fs.BaseDirectory[dir]}>{dir}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<input
|
||||
@@ -199,20 +219,21 @@
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn" on:click={open}>Open</button>
|
||||
<button class="btn" on:click={read}>Read</button>
|
||||
<button class="btn" on:click={mkdir}>Mkdir</button>
|
||||
<button class="btn" on:click={remove}>Remove</button>
|
||||
<button class="btn" onclick={open}>Open</button>
|
||||
<button class="btn" onclick={read}>Read</button>
|
||||
<button class="btn" onclick={mkdir}>Mkdir</button>
|
||||
<button class="btn" onclick={remove}>Remove</button>
|
||||
<div class="flex flex-row">
|
||||
<button class="btn" on:click={rename}>Rename</button>
|
||||
<button class="btn" onclick={rename}>Rename</button>
|
||||
<input class="input" bind:value={renameTo} placeholder="To" />
|
||||
</div>
|
||||
<button class="btn" type="button" on:click={setSrc}>Use as img src</button>
|
||||
<button class="btn" type="button" onclick={setSrc}>Use as img src</button>
|
||||
</div>
|
||||
{#if file}
|
||||
<div>
|
||||
<button class="btn" on:click={truncate}>Truncate</button>
|
||||
<button class="btn" on:click={stat}>Stat</button>
|
||||
<button class="btn" onclick={write}>Write</button>
|
||||
<button class="btn" onclick={truncate}>Truncate</button>
|
||||
<button class="btn" onclick={stat}>Stat</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -241,8 +262,8 @@
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn" on:click={watch}>Watch</button>
|
||||
<button class="btn" on:click={unwatch}>Unwatch</button>
|
||||
<button class="btn" onclick={watch}>Watch</button>
|
||||
<button class="btn" onclick={unwatch}>Unwatch</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<script>
|
||||
import { sendNotification } from '@tauri-apps/plugin-notification'
|
||||
export let onMessage
|
||||
|
||||
let sound = ''
|
||||
|
||||
// send the notification directly
|
||||
// the backend is responsible for checking the permission
|
||||
function _sendNotification() {
|
||||
new Notification('Notification title', {
|
||||
body: 'This is the notification body'
|
||||
sendNotification({
|
||||
title: 'Notification title',
|
||||
body: 'This is the notification body',
|
||||
sound: sound || null
|
||||
})
|
||||
}
|
||||
|
||||
// alternatively, check the permission ourselves
|
||||
function sendNotification() {
|
||||
function triggerNotification() {
|
||||
if (Notification.permission === 'default') {
|
||||
Notification.requestPermission()
|
||||
.then(function (response) {
|
||||
@@ -29,6 +34,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="btn" id="notification" on:click={sendNotification}>
|
||||
<input
|
||||
class="input grow"
|
||||
placeholder="Notification sound..."
|
||||
bind:value={sound}
|
||||
/>
|
||||
<button class="btn" id="notification" on:click={triggerNotification}>
|
||||
Send test notification
|
||||
</button>
|
||||
|
||||
+6
-5
@@ -11,20 +11,21 @@
|
||||
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.32.0",
|
||||
"@eslint/js": "9.36.0",
|
||||
"@rollup/plugin-node-resolve": "16.0.1",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-typescript": "12.1.4",
|
||||
"covector": "^0.12.4",
|
||||
"eslint": "9.32.0",
|
||||
"eslint": "9.36.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-security": "3.0.1",
|
||||
"prettier": "3.6.2",
|
||||
"rollup": "4.46.2",
|
||||
"rollup": "4.52.3",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.39.0"
|
||||
"typescript-eslint": "8.44.1"
|
||||
},
|
||||
"minimumReleaseAge": 4320,
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"esbuild@<0.25.0": ">=0.25.0"
|
||||
@@ -34,6 +35,6 @@
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": "^10.0.0"
|
||||
"pnpm": "^10.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.3]
|
||||
|
||||
- [`2522b71f`](https://github.com/tauri-apps/plugins-workspace/commit/2522b71f6bcae65c03b24415eb9295c9e7c84ffc) ([#2970](https://github.com/tauri-apps/plugins-workspace/pull/2970) by [@WSH032](https://github.com/tauri-apps/plugins-workspace/../../WSH032)) Revert the breaking change introduced by [#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928).
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
- [`21d721a0`](https://github.com/tauri-apps/plugins-workspace/commit/21d721a0c2731fc201872f5b99ea8bbdc61b0b60) ([#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Linux, improved error messages when OS commands fail.
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
- [`d4f8299b`](https://github.com/tauri-apps/plugins-workspace/commit/d4f8299b12f107718c70692840a63768d65baaf9) ([#2844](https://github.com/tauri-apps/plugins-workspace/pull/2844) by [@yobson1](https://github.com/tauri-apps/plugins-workspace/../../yobson1)) Fix deep link protocol handler not set as default on linux
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-deep-link"
|
||||
version = "2.4.1"
|
||||
version = "2.4.3"
|
||||
description = "Set your Tauri application as the default handler for an URL"
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -27,6 +27,9 @@ serde_json = { workspace = true }
|
||||
tauri-utils = { workspace = true }
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
|
||||
[target."cfg(target_os = \"macos\")".build-dependencies]
|
||||
plist = "1"
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
+119
-26
@@ -10,50 +10,64 @@ const COMMANDS: &[&str] = &["get_current", "register", "unregister", "is_registe
|
||||
|
||||
// TODO: Consider using activity-alias in case users may have multiple activities in their app.
|
||||
fn intent_filter(domain: &AssociatedDomain) -> String {
|
||||
let host = domain
|
||||
.host
|
||||
.as_ref()
|
||||
.map(|h| format!(r#"<data android:host="{h}" />"#))
|
||||
.unwrap_or_default();
|
||||
|
||||
let auto_verify = if domain.is_app_link() {
|
||||
r#"android:autoVerify="true" "#.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"<intent-filter android:autoVerify="true">
|
||||
r#"<intent-filter {auto_verify}>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
{}
|
||||
<data android:host="{}" />
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{schemes}
|
||||
{host}
|
||||
{domains}
|
||||
{path_patterns}
|
||||
{path_prefixes}
|
||||
{path_suffixes}
|
||||
</intent-filter>"#,
|
||||
domain
|
||||
schemes = domain
|
||||
.scheme
|
||||
.iter()
|
||||
.map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain.host,
|
||||
domain
|
||||
host = host,
|
||||
domains = domain
|
||||
.path
|
||||
.iter()
|
||||
.map(|path| format!(r#"<data android:path="{path}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_patterns = domain
|
||||
.path_pattern
|
||||
.iter()
|
||||
.map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_prefixes = domain
|
||||
.path_prefix
|
||||
.iter()
|
||||
.map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_suffixes = domain
|
||||
.path_suffix
|
||||
.iter()
|
||||
.map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
)
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -68,6 +82,16 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(config) = tauri_plugin::plugin_config::<Config>("deep-link") {
|
||||
let errors: Vec<String> = config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter_map(|d| d.validate().err())
|
||||
.collect();
|
||||
|
||||
if !errors.is_empty() {
|
||||
panic!("Deep link config validation failed:\n{}", errors.join("\n"));
|
||||
}
|
||||
|
||||
tauri_plugin::mobile::update_android_manifest(
|
||||
"DEEP LINK PLUGIN",
|
||||
"activity",
|
||||
@@ -80,20 +104,89 @@ fn main() {
|
||||
)
|
||||
.expect("failed to rewrite AndroidManifest.xml");
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.insert(
|
||||
"com.apple.developer.associated-domains".into(),
|
||||
config
|
||||
.mobile
|
||||
.into_iter()
|
||||
.map(|d| format!("applinks:{}", d.host).into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
// we need to ensure that the entitlements are only
|
||||
// generated for explicit app links and not
|
||||
// other deep links because then they
|
||||
// are just going to complain and not be built or signed
|
||||
let has_app_links = config.mobile.iter().any(|d| d.is_app_link());
|
||||
|
||||
if !has_app_links {
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.remove("com.apple.developer.associated-domains");
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
} else {
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.insert(
|
||||
"com.apple.developer.associated-domains".into(),
|
||||
config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter(|d| d.is_app_link())
|
||||
.filter_map(|d| d.host.as_ref())
|
||||
.map(|host| format!("applinks:{}", host).into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
}
|
||||
|
||||
let deep_link_domains = config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter_map(|domain| {
|
||||
if domain.is_app_link() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(domain)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if deep_link_domains.is_empty() {
|
||||
tauri_plugin::mobile::update_info_plist(|info_plist| {
|
||||
info_plist.remove("CFBundleURLTypes");
|
||||
})
|
||||
.expect("failed to update Info.plist");
|
||||
} else {
|
||||
tauri_plugin::mobile::update_info_plist(|info_plist| {
|
||||
info_plist.insert(
|
||||
"CFBundleURLTypes".into(),
|
||||
deep_link_domains
|
||||
.iter()
|
||||
.map(|domain| {
|
||||
let schemes = domain
|
||||
.scheme
|
||||
.iter()
|
||||
.filter(|scheme| {
|
||||
scheme.as_str() != "https" && scheme.as_str() != "http"
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut dict = plist::Dictionary::new();
|
||||
dict.insert(
|
||||
"CFBundleURLSchemes".into(),
|
||||
schemes
|
||||
.iter()
|
||||
.map(|s| s.to_string().into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
dict.insert(
|
||||
"CFBundleURLName".into(),
|
||||
format!("{}", domain.scheme[0]).into(),
|
||||
);
|
||||
plist::Value::Dictionary(dict)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update Info.plist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.2.6]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.3`
|
||||
|
||||
## \[2.2.5]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.2`
|
||||
|
||||
## \[2.2.4]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deep-link-example",
|
||||
"private": true,
|
||||
"version": "2.2.4",
|
||||
"version": "2.2.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -10,12 +10,12 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.7.0",
|
||||
"@tauri-apps/plugin-deep-link": "2.4.1"
|
||||
"@tauri-apps/api": "2.8.0",
|
||||
"@tauri-apps/plugin-deep-link": "2.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.7.1",
|
||||
"@tauri-apps/cli": "2.8.4",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^7.0.4"
|
||||
"vite": "^7.0.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
namespace = "com.tauri.deep_link_example"
|
||||
defaultConfig {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
applicationId = "com.tauri.deep_link_example"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
targetSdk = 36
|
||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||
}
|
||||
@@ -58,9 +58,10 @@ rust {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.webkit:webkit:1.6.1")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.8.0")
|
||||
implementation("androidx.webkit:webkit:1.14.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||
|
||||
+21
-4
@@ -23,23 +23,40 @@
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<intent-filter android:autoVerify="true" >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="http" />
|
||||
<data android:host="fabianlars.de" />
|
||||
|
||||
|
||||
<data android:pathPrefix="/intent" />
|
||||
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<intent-filter android:autoVerify="true" >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="http" />
|
||||
<data android:host="tauri.app" />
|
||||
|
||||
|
||||
|
||||
|
||||
</intent-filter>
|
||||
<intent-filter >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="taurideeplink" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</intent-filter>
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
</activity>
|
||||
|
||||
+9
-5
@@ -1,7 +1,11 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package com.tauri.deep_link_example
|
||||
|
||||
class MainActivity : TauriActivity()
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
|
||||
class MainActivity : TauriActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:8.5.1")
|
||||
classpath("com.android.tools.build:gradle:8.11.0")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
compileOnly(gradleApi())
|
||||
implementation("com.android.tools.build:gradle:8.5.1")
|
||||
implementation("com.android.tools.build:gradle:8.11.0")
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Tue May 10 19:22:52 CST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+77
-77
@@ -1,116 +1,116 @@
|
||||
{
|
||||
"images": [
|
||||
"images" : [
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-20x20@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-20x20@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-29x29@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-29x29@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-40x40@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-40x40@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-60x60@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-60x60@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-20x20@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-20x20@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-29x29@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-29x29@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-40x40@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-40x40@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-76x76@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-76x76@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-83.5x83.5@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "1024x1024",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": "AppIcon-512@2x.png",
|
||||
"scale": "1x"
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
|
||||
+12
-34
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objectVersion = 63;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -167,6 +167,8 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = "deep-link-example_iOS";
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = "deep-link-example_iOS";
|
||||
productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@@ -189,6 +191,7 @@
|
||||
en,
|
||||
);
|
||||
mainGroup = 1DC58B1705AA3ECC6B887FE7;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
@@ -227,7 +230,6 @@
|
||||
outputPaths = (
|
||||
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
|
||||
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
|
||||
"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -314,18 +316,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = (
|
||||
arm64,
|
||||
"arm64-sim",
|
||||
);
|
||||
ARCHS = arm64;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\".\"",
|
||||
@@ -335,13 +332,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||
@@ -360,7 +350,7 @@
|
||||
PRODUCT_NAME = "deep-link-example";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = "arm64 arm64-sim";
|
||||
VALID_ARCHS = arm64;
|
||||
};
|
||||
name = debug;
|
||||
};
|
||||
@@ -424,18 +414,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = (
|
||||
arm64,
|
||||
"arm64-sim",
|
||||
);
|
||||
ARCHS = arm64;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\".\"",
|
||||
@@ -445,13 +430,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||
@@ -470,7 +448,7 @@
|
||||
PRODUCT_NAME = "deep-link-example";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = "arm64 arm64-sim";
|
||||
VALID_ARCHS = arm64;
|
||||
};
|
||||
name = release;
|
||||
};
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+12
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.0</string>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
@@ -40,5 +40,16 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>taurideeplink</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>taurideeplink</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,7 +1,3 @@
|
||||
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: deep-link-example
|
||||
options:
|
||||
bundleIdPrefix: com.tauri.deep-link-example
|
||||
@@ -16,7 +12,6 @@ settingGroups:
|
||||
base:
|
||||
PRODUCT_NAME: deep-link-example
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example
|
||||
DEVELOPMENT_TEAM: Q93MBH6S2F
|
||||
targetTemplates:
|
||||
app:
|
||||
type: application
|
||||
@@ -56,8 +51,8 @@ targets:
|
||||
- UIInterfaceOrientationPortraitUpsideDown
|
||||
- UIInterfaceOrientationLandscapeLeft
|
||||
- UIInterfaceOrientationLandscapeRight
|
||||
CFBundleShortVersionString: 0.0.0
|
||||
CFBundleVersion: 0.0.0
|
||||
CFBundleShortVersionString: 0.1.0
|
||||
CFBundleVersion: '0.1.0'
|
||||
entitlements:
|
||||
path: deep-link-example_iOS/deep-link-example_iOS.entitlements
|
||||
scheme:
|
||||
@@ -67,14 +62,12 @@ targets:
|
||||
settings:
|
||||
base:
|
||||
ENABLE_BITCODE: false
|
||||
ARCHS: [arm64, arm64-sim]
|
||||
VALID_ARCHS: arm64 arm64-sim
|
||||
ARCHS: [arm64]
|
||||
VALID_ARCHS: arm64
|
||||
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
|
||||
EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
||||
groups: [app]
|
||||
dependencies:
|
||||
- framework: libapp.a
|
||||
@@ -93,4 +86,3 @@ targets:
|
||||
outputFiles:
|
||||
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
|
||||
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
|
||||
- $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
},
|
||||
{
|
||||
"host": "tauri.app"
|
||||
},
|
||||
{
|
||||
"scheme": ["taurideeplink"]
|
||||
}
|
||||
],
|
||||
"desktop": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-deep-link",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.3",
|
||||
"description": "Set your Tauri application as the default handler for an URL",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
@@ -25,6 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.8.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ use tauri_utils::config::DeepLinkProtocol;
|
||||
pub struct AssociatedDomain {
|
||||
#[serde(default = "default_schemes")]
|
||||
pub scheme: Vec<String>,
|
||||
|
||||
#[serde(deserialize_with = "deserialize_associated_host")]
|
||||
pub host: String,
|
||||
|
||||
#[serde(default, deserialize_with = "deserialize_associated_host")]
|
||||
pub host: Option<String>, // Optional custom uri schemes dont NEED a host (may have one still), but required for https/http schemes
|
||||
#[serde(default)]
|
||||
pub path: Vec<String>,
|
||||
#[serde(default, alias = "path-pattern", rename = "pathPattern")]
|
||||
@@ -23,6 +21,41 @@ pub struct AssociatedDomain {
|
||||
pub path_prefix: Vec<String>,
|
||||
#[serde(default, alias = "path-suffix", rename = "pathSuffix")]
|
||||
pub path_suffix: Vec<String>,
|
||||
#[serde(default, alias = "app-link", rename = "appLink")]
|
||||
pub app_link: Option<bool>,
|
||||
}
|
||||
|
||||
impl AssociatedDomain {
|
||||
/// Returns true if the domain uses http or https scheme.
|
||||
pub fn is_web_link(&self) -> bool {
|
||||
self.scheme.iter().any(|s| s == "https" || s == "http")
|
||||
}
|
||||
|
||||
/// Returns true if the domain uses http or https scheme and has proper host configuration.
|
||||
pub fn is_app_link(&self) -> bool {
|
||||
self.app_link
|
||||
.unwrap_or_else(|| self.is_web_link() && self.host.is_some())
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
// Rule 1: All web links require a host.
|
||||
if self.is_web_link() && self.host.is_none() {
|
||||
return Err("Web link requires a host".into());
|
||||
}
|
||||
|
||||
// Rule 2: If it's an App Link, ensure http(s) and host.
|
||||
if self.is_app_link() {
|
||||
if !self.is_web_link() {
|
||||
return Err("AppLink must be a valid web link (https/http + host)".into());
|
||||
}
|
||||
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
|
||||
{
|
||||
eprintln!("Warning: AppLink uses only 'http' — allowed on Android but not secure for production.");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Consider removing this in v3
|
||||
@@ -30,18 +63,19 @@ fn default_schemes() -> Vec<String> {
|
||||
vec!["https".to_string(), "http".to_string()]
|
||||
}
|
||||
|
||||
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let host = String::deserialize(deserializer)?;
|
||||
if let Some((scheme, _host)) = host.split_once("://") {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||
)))
|
||||
} else {
|
||||
Ok(host)
|
||||
let opt = Option::<String>::deserialize(deserializer)?;
|
||||
if let Some(ref host) = opt {
|
||||
if let Some((scheme, _)) = host.split_once("://") {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(opt)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
|
||||
@@ -28,6 +28,16 @@ pub enum Error {
|
||||
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
|
||||
}
|
||||
|
||||
// TODO(v3): change this into an error in v3,
|
||||
// see <https://github.com/tauri-apps/plugins-workspace/pull/2970#issuecomment-3244660138>.
|
||||
#[inline]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) fn inspect_command_error<'a>(command: &'a str) -> impl Fn(&std::io::Error) + 'a {
|
||||
move |e| {
|
||||
tracing::error!("Failed to run OS command `{command}`: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
|
||||
@@ -254,6 +254,7 @@ mod imp {
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Linux**: Needs the `xdg-mime` and `update-desktop-database` commands available on the system.
|
||||
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||
pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> {
|
||||
#[cfg(windows)]
|
||||
@@ -292,6 +293,7 @@ mod imp {
|
||||
.unwrap_or_else(|| bin.into_os_string())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let qualified_exec = format!("{} %u", exec);
|
||||
|
||||
let target = self.app.path().data_dir()?.join("applications");
|
||||
|
||||
@@ -303,12 +305,28 @@ mod imp {
|
||||
|
||||
if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) {
|
||||
if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) {
|
||||
// it's ok to remove it - we only write to the file if it's missing
|
||||
// and in that case we include old_mimes
|
||||
let old_mimes = section.remove("MimeType").unwrap_or_default();
|
||||
let mut change = false;
|
||||
|
||||
// if the mime type is not present, append it to the list
|
||||
if !old_mimes.split(';').any(|mime| mime == mime_type) {
|
||||
section.append("MimeType", format!("{mime_type};{old_mimes}"));
|
||||
change = true;
|
||||
} else {
|
||||
section.insert("MimeType".to_string(), old_mimes);
|
||||
}
|
||||
|
||||
// if the exec command doesnt match, update to the new one
|
||||
let old_exec = section.remove("Exec").unwrap_or_default();
|
||||
if old_exec != qualified_exec {
|
||||
section.append("Exec", qualified_exec);
|
||||
change = true;
|
||||
} else {
|
||||
section.insert("Exec".to_string(), old_exec.to_string());
|
||||
}
|
||||
|
||||
// if any property has changed, rewrite the .desktop file
|
||||
if change {
|
||||
desktop_file.write_to_file(&target_file)?;
|
||||
}
|
||||
}
|
||||
@@ -323,7 +341,7 @@ mod imp {
|
||||
.product_name
|
||||
.clone()
|
||||
.unwrap_or_else(|| file_name.clone()),
|
||||
exec = exec,
|
||||
qualified_exec = qualified_exec,
|
||||
mime_type = mime_type
|
||||
)
|
||||
.as_bytes(),
|
||||
@@ -332,11 +350,15 @@ mod imp {
|
||||
|
||||
Command::new("update-desktop-database")
|
||||
.arg(target)
|
||||
.status()?;
|
||||
.status()
|
||||
.inspect_err(crate::error::inspect_command_error(
|
||||
"update-desktop-database",
|
||||
))?;
|
||||
|
||||
Command::new("xdg-mime")
|
||||
.args(["default", &file_name, mime_type.as_str()])
|
||||
.status()?;
|
||||
.status()
|
||||
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -405,6 +427,7 @@ mod imp {
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Linux**: Needs the `xdg-mime` command available on the system.
|
||||
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||
pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> {
|
||||
#[cfg(windows)]
|
||||
@@ -439,7 +462,8 @@ mod imp {
|
||||
"default",
|
||||
&format!("x-scheme-handler/{}", _protocol.as_ref()),
|
||||
])
|
||||
.output()?;
|
||||
.output()
|
||||
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).contains(&file_name))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name={name}
|
||||
Exec={exec} %u
|
||||
Exec={qualified_exec}
|
||||
Terminal=false
|
||||
MimeType={mime_type}
|
||||
NoDisplay=true
|
||||
NoDisplay=true
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`509eba8d`](https://github.com/tauri-apps/plugins-workspace/commit/509eba8d441c4f6ecf0af77b572cb2afd69a752d) ([#2641](https://github.com/tauri-apps/plugins-workspace/pull/2641) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Add support for showing a message dialog with 3 buttons.
|
||||
|
||||
## \[2.3.3]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.2`
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`af08c66f`](https://github.com/tauri-apps/plugins-workspace/commit/af08c66faafe0dffc4b0a80aef030cd3f0f89a9c) ([#2871](https://github.com/tauri-apps/plugins-workspace/pull/2871) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused the file picker not to open on Android when extension filters were set.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.3.2"
|
||||
version = "2.4.0"
|
||||
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -34,7 +34,7 @@ tauri = { workspace = true }
|
||||
log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
|
||||
tauri-plugin-fs = { path = "../fs", version = "2.4.2" }
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
tauri = { workspace = true, features = ["wry"] }
|
||||
|
||||
@@ -38,6 +38,7 @@ class MessageOptions {
|
||||
var title: String? = null
|
||||
lateinit var message: String
|
||||
var okButtonLabel: String? = null
|
||||
var noButtonLabel: String? = null
|
||||
var cancelButtonLabel: String? = null
|
||||
}
|
||||
|
||||
@@ -139,9 +140,8 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
return
|
||||
}
|
||||
|
||||
val handler = { cancelled: Boolean, value: Boolean ->
|
||||
val handler = { value: String ->
|
||||
val ret = JSObject()
|
||||
ret.put("cancelled", cancelled)
|
||||
ret.put("value", value)
|
||||
invoke.resolve(ret)
|
||||
}
|
||||
@@ -153,24 +153,34 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
if (args.title != null) {
|
||||
builder.setTitle(args.title)
|
||||
}
|
||||
|
||||
val okButtonLabel = args.okButtonLabel ?: "Ok"
|
||||
|
||||
builder
|
||||
.setMessage(args.message)
|
||||
.setPositiveButton(
|
||||
args.okButtonLabel ?: "OK"
|
||||
) { dialog, _ ->
|
||||
.setPositiveButton(okButtonLabel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
handler(false, true)
|
||||
handler(okButtonLabel)
|
||||
}
|
||||
.setOnCancelListener { dialog ->
|
||||
dialog.dismiss()
|
||||
handler(true, false)
|
||||
handler(args.cancelButtonLabel ?: "Cancel")
|
||||
}
|
||||
|
||||
if (args.noButtonLabel != null) {
|
||||
builder.setNeutralButton(args.noButtonLabel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
handler(args.noButtonLabel!!)
|
||||
}
|
||||
}
|
||||
|
||||
if (args.cancelButtonLabel != null) {
|
||||
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
handler(false, false)
|
||||
handler(args.cancelButtonLabel!!)
|
||||
}
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,yesButtonLabel:i?.okLabel?.toString(),noButtonLabel:i?.cancelLabel?.toString()})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),cancelButtonLabel:i?.cancelLabel?.toString()})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}function e(t){if(void 0!==t)return"string"==typeof t?t:"ok"in t&&"cancel"in t?{OkCancelCustom:[t.ok,t.cancel]}:"yes"in t&&"no"in t&&"cancel"in t?{YesNoCancelCustom:[t.yes,t.no,t.cancel]}:"ok"in t?{OkCustom:t.ok}:void 0}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,yesButtonLabel:o?.okLabel?.toString(),noButtonLabel:o?.cancelLabel?.toString()})},t.confirm=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,okButtonLabel:o?.okLabel?.toString(),cancelButtonLabel:o?.cancelLabel?.toString()})},t.message=async function(t,o){const i="string"==typeof o?{title:o}:o;return n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),buttons:e(i?.buttons)})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
|
||||
|
||||
@@ -77,6 +77,80 @@ interface SaveDialogOptions {
|
||||
canCreateDirectories?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Default buttons for a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogDefaultButtons =
|
||||
| 'Ok'
|
||||
| 'OkCancel'
|
||||
| 'YesNo'
|
||||
| 'YesNoCancel'
|
||||
|
||||
/** All possible button keys. */
|
||||
type ButtonKey = 'ok' | 'cancel' | 'yes' | 'no'
|
||||
|
||||
/** Ban everything except a set of keys. */
|
||||
type BanExcept<Allowed extends ButtonKey> = Partial<
|
||||
Record<Exclude<ButtonKey, Allowed>, never>
|
||||
>
|
||||
|
||||
/**
|
||||
* The Yes, No and Cancel buttons of a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogButtonsYesNoCancel = {
|
||||
/** The Yes button. */
|
||||
yes: string
|
||||
/** The No button. */
|
||||
no: string
|
||||
/** The Cancel button. */
|
||||
cancel: string
|
||||
} & BanExcept<'yes' | 'no' | 'cancel'>
|
||||
|
||||
/**
|
||||
* The Ok and Cancel buttons of a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogButtonsOkCancel = {
|
||||
/** The Ok button. */
|
||||
ok: string
|
||||
/** The Cancel button. */
|
||||
cancel: string
|
||||
} & BanExcept<'ok' | 'cancel'>
|
||||
|
||||
/**
|
||||
* The Ok button of a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogButtonsOk = {
|
||||
/** The Ok button. */
|
||||
ok: string
|
||||
} & BanExcept<'ok'>
|
||||
|
||||
/**
|
||||
* Custom buttons for a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogCustomButtons =
|
||||
| MessageDialogButtonsYesNoCancel
|
||||
| MessageDialogButtonsOkCancel
|
||||
| MessageDialogButtonsOk
|
||||
|
||||
/**
|
||||
* The buttons of a message dialog.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogButtons =
|
||||
| MessageDialogDefaultButtons
|
||||
| MessageDialogCustomButtons
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@@ -85,8 +159,58 @@ interface MessageDialogOptions {
|
||||
title?: string
|
||||
/** The kind of the dialog. Defaults to `info`. */
|
||||
kind?: 'info' | 'warning' | 'error'
|
||||
/** The label of the confirm button. */
|
||||
/**
|
||||
* The label of the Ok button.
|
||||
*
|
||||
* @deprecated Use {@linkcode MessageDialogOptions.buttons} instead.
|
||||
*/
|
||||
okLabel?: string
|
||||
/**
|
||||
* The buttons of the dialog.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* // Use system default buttons texts
|
||||
* await message('Hello World!', { buttons: 'Ok' })
|
||||
* await message('Hello World!', { buttons: 'OkCancel' })
|
||||
*
|
||||
* // Or with custom button texts
|
||||
* await message('Hello World!', { buttons: { ok: 'Yes!' } })
|
||||
* await message('Take on the task?', {
|
||||
* buttons: { ok: 'Accept', cancel: 'Cancel' }
|
||||
* })
|
||||
* await message('Show the file content?', {
|
||||
* buttons: { yes: 'Show content', no: 'Show in folder', cancel: 'Cancel' }
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
buttons?: MessageDialogButtons
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to convert the buttons to the Rust type.
|
||||
*/
|
||||
function buttonsToRust(buttons: MessageDialogButtons | undefined) {
|
||||
if (buttons === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (typeof buttons === 'string') {
|
||||
return buttons
|
||||
} else if ('ok' in buttons && 'cancel' in buttons) {
|
||||
return { OkCancelCustom: [buttons.ok, buttons.cancel] }
|
||||
} else if ('yes' in buttons && 'no' in buttons && 'cancel' in buttons) {
|
||||
return {
|
||||
YesNoCancelCustom: [buttons.yes, buttons.no, buttons.cancel]
|
||||
}
|
||||
} else if ('ok' in buttons) {
|
||||
return { OkCustom: buttons.ok }
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
interface ConfirmDialogOptions {
|
||||
@@ -202,6 +326,16 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
|
||||
return await invoke('plugin:dialog|save', { options })
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of a message dialog.
|
||||
*
|
||||
* The result is a string if the dialog has custom buttons,
|
||||
* otherwise it is one of the default buttons.
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
|
||||
|
||||
/**
|
||||
* Shows a message dialog with an `Ok` button.
|
||||
* @example
|
||||
@@ -222,13 +356,15 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
|
||||
async function message(
|
||||
message: string,
|
||||
options?: string | MessageDialogOptions
|
||||
): Promise<void> {
|
||||
): Promise<MessageDialogResult> {
|
||||
const opts = typeof options === 'string' ? { title: options } : options
|
||||
await invoke('plugin:dialog|message', {
|
||||
|
||||
return invoke<MessageDialogResult>('plugin:dialog|message', {
|
||||
message: message.toString(),
|
||||
title: opts?.title?.toString(),
|
||||
kind: opts?.kind,
|
||||
okButtonLabel: opts?.okLabel?.toString()
|
||||
okButtonLabel: opts?.okLabel?.toString(),
|
||||
buttons: buttonsToRust(opts?.buttons)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ struct MessageDialogOptions: Decodable {
|
||||
var title: String?
|
||||
let message: String
|
||||
var okButtonLabel: String?
|
||||
var noButtonLabel: String?
|
||||
var cancelButtonLabel: String?
|
||||
}
|
||||
|
||||
@@ -200,36 +201,38 @@ class DialogPlugin: Plugin {
|
||||
let alert = UIAlertController(
|
||||
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
|
||||
|
||||
let cancelButtonLabel = args.cancelButtonLabel ?? ""
|
||||
if !cancelButtonLabel.isEmpty {
|
||||
if let cancelButtonLabel = args.cancelButtonLabel {
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: cancelButtonLabel, style: UIAlertAction.Style.default,
|
||||
handler: { (_) -> Void in
|
||||
Logger.error("cancel")
|
||||
|
||||
invoke.resolve([
|
||||
"value": false,
|
||||
"cancelled": false,
|
||||
])
|
||||
}))
|
||||
invoke.resolve(["value": cancelButtonLabel])
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let okButtonLabel = args.okButtonLabel ?? (cancelButtonLabel.isEmpty ? "OK" : "")
|
||||
if !okButtonLabel.isEmpty {
|
||||
if let noButtonLabel = args.noButtonLabel {
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: okButtonLabel, style: UIAlertAction.Style.default,
|
||||
title: noButtonLabel, style: UIAlertAction.Style.default,
|
||||
handler: { (_) -> Void in
|
||||
Logger.error("ok")
|
||||
|
||||
invoke.resolve([
|
||||
"value": true,
|
||||
"cancelled": false,
|
||||
])
|
||||
}))
|
||||
invoke.resolve(["value": noButtonLabel])
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
let okButtonLabel = args.okButtonLabel ?? "Ok"
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: okButtonLabel, style: UIAlertAction.Style.default,
|
||||
handler: { (_) -> Void in
|
||||
invoke.resolve(["value": okButtonLabel])
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
manager.viewController?.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-dialog",
|
||||
"version": "2.3.2",
|
||||
"version": "2.4.0",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ use tauri::{command, Manager, Runtime, State, Window};
|
||||
use tauri_plugin_fs::FsExt;
|
||||
|
||||
use crate::{
|
||||
Dialog, FileDialogBuilder, FilePath, MessageDialogButtons, MessageDialogKind, Result, CANCEL,
|
||||
NO, OK, YES,
|
||||
Dialog, FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogButtons,
|
||||
MessageDialogKind, MessageDialogResult, Result, CANCEL, NO, OK, YES,
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -248,7 +248,7 @@ fn message_dialog<R: Runtime>(
|
||||
message: String,
|
||||
kind: Option<MessageDialogKind>,
|
||||
buttons: MessageDialogButtons,
|
||||
) -> bool {
|
||||
) -> MessageDialogBuilder<R> {
|
||||
let mut builder = dialog.message(message);
|
||||
|
||||
builder = builder.buttons(buttons);
|
||||
@@ -266,7 +266,7 @@ fn message_dialog<R: Runtime>(
|
||||
builder = builder.kind(kind);
|
||||
}
|
||||
|
||||
builder.blocking_show()
|
||||
builder
|
||||
}
|
||||
|
||||
#[command]
|
||||
@@ -277,19 +277,15 @@ pub(crate) async fn message<R: Runtime>(
|
||||
message: String,
|
||||
kind: Option<MessageDialogKind>,
|
||||
ok_button_label: Option<String>,
|
||||
) -> Result<bool> {
|
||||
Ok(message_dialog(
|
||||
window,
|
||||
dialog,
|
||||
title,
|
||||
message,
|
||||
kind,
|
||||
if let Some(ok_button_label) = ok_button_label {
|
||||
MessageDialogButtons::OkCustom(ok_button_label)
|
||||
} else {
|
||||
MessageDialogButtons::Ok
|
||||
},
|
||||
))
|
||||
buttons: Option<MessageDialogButtons>,
|
||||
) -> Result<MessageDialogResult> {
|
||||
let buttons = buttons.unwrap_or(if let Some(ok_button_label) = ok_button_label {
|
||||
MessageDialogButtons::OkCustom(ok_button_label)
|
||||
} else {
|
||||
MessageDialogButtons::Ok
|
||||
});
|
||||
|
||||
Ok(message_dialog(window, dialog, title, message, kind, buttons).blocking_show_with_result())
|
||||
}
|
||||
|
||||
#[command]
|
||||
@@ -302,7 +298,7 @@ pub(crate) async fn ask<R: Runtime>(
|
||||
yes_button_label: Option<String>,
|
||||
no_button_label: Option<String>,
|
||||
) -> Result<bool> {
|
||||
Ok(message_dialog(
|
||||
let dialog = message_dialog(
|
||||
window,
|
||||
dialog,
|
||||
title,
|
||||
@@ -318,7 +314,9 @@ pub(crate) async fn ask<R: Runtime>(
|
||||
} else {
|
||||
MessageDialogButtons::YesNo
|
||||
},
|
||||
))
|
||||
);
|
||||
|
||||
Ok(dialog.blocking_show())
|
||||
}
|
||||
|
||||
#[command]
|
||||
@@ -331,7 +329,7 @@ pub(crate) async fn confirm<R: Runtime>(
|
||||
ok_button_label: Option<String>,
|
||||
cancel_button_label: Option<String>,
|
||||
) -> Result<bool> {
|
||||
Ok(message_dialog(
|
||||
let dialog = message_dialog(
|
||||
window,
|
||||
dialog,
|
||||
title,
|
||||
@@ -347,5 +345,7 @@ pub(crate) async fn confirm<R: Runtime>(
|
||||
} else {
|
||||
MessageDialogButtons::OkCancel
|
||||
},
|
||||
))
|
||||
);
|
||||
|
||||
Ok(dialog.blocking_show())
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use rfd::{AsyncFileDialog, AsyncMessageDialog};
|
||||
use serde::de::DeserializeOwned;
|
||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
||||
|
||||
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder, OK};
|
||||
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder};
|
||||
|
||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||
app: &AppHandle<R>,
|
||||
@@ -115,6 +115,10 @@ impl From<MessageDialogButtons> for rfd::MessageButtons {
|
||||
MessageDialogButtons::YesNo => Self::YesNo,
|
||||
MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok),
|
||||
MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel),
|
||||
MessageDialogButtons::YesNoCancel => Self::YesNoCancel,
|
||||
MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
|
||||
Self::YesNoCancelCustom(yes, no, cancel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,28 +212,46 @@ pub fn save_file<R: Runtime, F: FnOnce(Option<FilePath>) + Send + 'static>(
|
||||
}
|
||||
|
||||
/// Shows a message dialog
|
||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(MessageDialogResult) + Send + 'static>(
|
||||
dialog: MessageDialogBuilder<R>,
|
||||
f: F,
|
||||
callback: F,
|
||||
) {
|
||||
use rfd::MessageDialogResult;
|
||||
|
||||
let ok_label = match &dialog.buttons {
|
||||
MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
|
||||
MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
|
||||
_ => None,
|
||||
};
|
||||
let f = move |res| {
|
||||
f(match res {
|
||||
MessageDialogResult::Ok | MessageDialogResult::Yes => true,
|
||||
MessageDialogResult::Custom(s) => ok_label.map_or(s == OK, |ok_label| ok_label == s),
|
||||
_ => false,
|
||||
});
|
||||
};
|
||||
let f = move |res: rfd::MessageDialogResult| callback(res.into());
|
||||
|
||||
let handle = dialog.dialog.app_handle().to_owned();
|
||||
let _ = handle.run_on_main_thread(move || {
|
||||
let buttons = dialog.buttons.clone();
|
||||
let dialog = AsyncMessageDialog::from(dialog).show();
|
||||
std::thread::spawn(move || f(tauri::async_runtime::block_on(dialog)));
|
||||
std::thread::spawn(move || {
|
||||
let result = tauri::async_runtime::block_on(dialog);
|
||||
// on Linux rfd does not return rfd::MessageDialogResult::Custom, so we must map manually
|
||||
let result = match (result, buttons) {
|
||||
(rfd::MessageDialogResult::Ok, MessageDialogButtons::OkCustom(s)) => {
|
||||
rfd::MessageDialogResult::Custom(s)
|
||||
}
|
||||
(
|
||||
rfd::MessageDialogResult::Ok,
|
||||
MessageDialogButtons::OkCancelCustom(ok, _cancel),
|
||||
) => rfd::MessageDialogResult::Custom(ok),
|
||||
(
|
||||
rfd::MessageDialogResult::Cancel,
|
||||
MessageDialogButtons::OkCancelCustom(_ok, cancel),
|
||||
) => rfd::MessageDialogResult::Custom(cancel),
|
||||
(
|
||||
rfd::MessageDialogResult::Yes,
|
||||
MessageDialogButtons::YesNoCancelCustom(yes, _no, _cancel),
|
||||
) => rfd::MessageDialogResult::Custom(yes),
|
||||
(
|
||||
rfd::MessageDialogResult::No,
|
||||
MessageDialogButtons::YesNoCancelCustom(_yes, no, _cancel),
|
||||
) => rfd::MessageDialogResult::Custom(no),
|
||||
(
|
||||
rfd::MessageDialogResult::Cancel,
|
||||
MessageDialogButtons::YesNoCancelCustom(_yes, _no, cancel),
|
||||
) => rfd::MessageDialogResult::Custom(cancel),
|
||||
(result, _) => result,
|
||||
};
|
||||
f(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ pub(crate) struct MessageDialogPayload<'a> {
|
||||
message: &'a String,
|
||||
kind: &'a MessageDialogKind,
|
||||
ok_button_label: Option<&'a str>,
|
||||
no_button_label: Option<&'a str>,
|
||||
cancel_button_label: Option<&'a str>,
|
||||
}
|
||||
|
||||
@@ -238,13 +239,17 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
||||
|
||||
#[cfg(mobile)]
|
||||
pub(crate) fn payload(&self) -> MessageDialogPayload<'_> {
|
||||
let (ok_button_label, cancel_button_label) = match &self.buttons {
|
||||
MessageDialogButtons::Ok => (Some(OK), None),
|
||||
MessageDialogButtons::OkCancel => (Some(OK), Some(CANCEL)),
|
||||
MessageDialogButtons::YesNo => (Some(YES), Some(NO)),
|
||||
MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), Some(CANCEL)),
|
||||
let (ok_button_label, no_button_label, cancel_button_label) = match &self.buttons {
|
||||
MessageDialogButtons::Ok => (Some(OK), None, None),
|
||||
MessageDialogButtons::OkCancel => (Some(OK), None, Some(CANCEL)),
|
||||
MessageDialogButtons::YesNo => (Some(YES), Some(NO), None),
|
||||
MessageDialogButtons::YesNoCancel => (Some(YES), Some(NO), Some(CANCEL)),
|
||||
MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), None, None),
|
||||
MessageDialogButtons::OkCancelCustom(ok, cancel) => {
|
||||
(Some(ok.as_str()), Some(cancel.as_str()))
|
||||
(Some(ok.as_str()), None, Some(cancel.as_str()))
|
||||
}
|
||||
MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
|
||||
(Some(yes.as_str()), Some(no.as_str()), Some(cancel.as_str()))
|
||||
}
|
||||
};
|
||||
MessageDialogPayload {
|
||||
@@ -252,6 +257,7 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
||||
message: &self.message,
|
||||
kind: &self.kind,
|
||||
ok_button_label,
|
||||
no_button_label,
|
||||
cancel_button_label,
|
||||
}
|
||||
}
|
||||
@@ -295,16 +301,55 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
||||
}
|
||||
|
||||
/// Shows a message dialog
|
||||
///
|
||||
/// Returns `true` if the user pressed the OK/Yes button,
|
||||
pub fn show<F: FnOnce(bool) + Send + 'static>(self, f: F) {
|
||||
let ok_label = match &self.buttons {
|
||||
MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
|
||||
MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
|
||||
MessageDialogButtons::YesNoCancelCustom(yes, _, _) => Some(yes.clone()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
show_message_dialog(self, move |res| {
|
||||
let sucess = match res {
|
||||
MessageDialogResult::Ok | MessageDialogResult::Yes => true,
|
||||
MessageDialogResult::Custom(s) => {
|
||||
ok_label.map_or(s == OK, |ok_label| ok_label == s)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
f(sucess)
|
||||
})
|
||||
}
|
||||
|
||||
/// Shows a message dialog and returns the button that was pressed.
|
||||
///
|
||||
/// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
|
||||
pub fn show_with_result<F: FnOnce(MessageDialogResult) + Send + 'static>(self, f: F) {
|
||||
show_message_dialog(self, f)
|
||||
}
|
||||
|
||||
/// Shows a message dialog.
|
||||
///
|
||||
/// Returns `true` if the user pressed the OK/Yes button,
|
||||
///
|
||||
/// This is a blocking operation,
|
||||
/// and should *NOT* be used when running on the main thread context.
|
||||
pub fn blocking_show(self) -> bool {
|
||||
blocking_fn!(self, show)
|
||||
}
|
||||
|
||||
/// Shows a message dialog and returns the button that was pressed.
|
||||
///
|
||||
/// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
|
||||
///
|
||||
/// This is a blocking operation,
|
||||
/// and should *NOT* be used when running on the main thread context.
|
||||
pub fn blocking_show_with_result(self) -> MessageDialogResult {
|
||||
blocking_fn!(self, show_with_result)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(crate) struct Filter {
|
||||
|
||||
@@ -8,7 +8,7 @@ use tauri::{
|
||||
AppHandle, Runtime,
|
||||
};
|
||||
|
||||
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder};
|
||||
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
const PLUGIN_IDENTIFIER: &str = "app.tauri.dialog";
|
||||
@@ -107,13 +107,11 @@ pub fn save_file<R: Runtime, F: FnOnce(Option<FilePath>) + Send + 'static>(
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ShowMessageDialogResponse {
|
||||
#[allow(dead_code)]
|
||||
cancelled: bool,
|
||||
value: bool,
|
||||
value: String,
|
||||
}
|
||||
|
||||
/// Shows a message dialog
|
||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(MessageDialogResult) + Send + 'static>(
|
||||
dialog: MessageDialogBuilder<R>,
|
||||
f: F,
|
||||
) {
|
||||
@@ -122,6 +120,8 @@ pub fn show_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
||||
.dialog
|
||||
.0
|
||||
.run_mobile_plugin::<ShowMessageDialogResponse>("showMessageDialog", dialog.payload());
|
||||
f(res.map(|r| r.value).unwrap_or_default())
|
||||
|
||||
let res = res.map(|res| res.value.into());
|
||||
f(res.unwrap_or_default())
|
||||
});
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ impl Serialize for MessageDialogKind {
|
||||
|
||||
/// Set of button that will be displayed on the dialog
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub enum MessageDialogButtons {
|
||||
#[default]
|
||||
/// A single `Ok` button with OS default dialog text
|
||||
@@ -61,8 +61,49 @@ pub enum MessageDialogButtons {
|
||||
OkCancel,
|
||||
/// 2 buttons `Yes` and `No` with OS default dialog texts
|
||||
YesNo,
|
||||
/// 3 buttons `Yes`, `No` and `Cancel` with OS default dialog texts
|
||||
YesNoCancel,
|
||||
/// A single `Ok` button with custom text
|
||||
OkCustom(String),
|
||||
/// 2 buttons `Ok` and `Cancel` with custom texts
|
||||
OkCancelCustom(String, String),
|
||||
/// 3 buttons `Yes`, `No` and `Cancel` with custom texts
|
||||
YesNoCancelCustom(String, String, String),
|
||||
}
|
||||
|
||||
/// Result of a message dialog
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum MessageDialogResult {
|
||||
Yes,
|
||||
No,
|
||||
Ok,
|
||||
#[default]
|
||||
Cancel,
|
||||
#[serde(untagged)]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
#[cfg(desktop)]
|
||||
impl From<rfd::MessageDialogResult> for MessageDialogResult {
|
||||
fn from(result: rfd::MessageDialogResult) -> Self {
|
||||
match result {
|
||||
rfd::MessageDialogResult::Yes => Self::Yes,
|
||||
rfd::MessageDialogResult::No => Self::No,
|
||||
rfd::MessageDialogResult::Ok => Self::Ok,
|
||||
rfd::MessageDialogResult::Cancel => Self::Cancel,
|
||||
rfd::MessageDialogResult::Custom(s) => Self::Custom(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for MessageDialogResult {
|
||||
fn from(value: String) -> Self {
|
||||
match value.as_str() {
|
||||
"Yes" => Self::Yes,
|
||||
"No" => Self::No,
|
||||
"Ok" => Self::Ok,
|
||||
"Cancel" => Self::Cancel,
|
||||
_ => Self::Custom(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
- [`4eb36b0f`](https://github.com/tauri-apps/plugins-workspace/commit/4eb36b0ff57acb0bb1b911c583efa3bf2f56aa32) ([#2907](https://github.com/tauri-apps/plugins-workspace/pull/2907) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fixed calling `writeFile` with `data: ReadableStream` throws `Invalid argument`
|
||||
- [`515182a1`](https://github.com/tauri-apps/plugins-workspace/commit/515182a179d4439079b2b7f6927555ba5ab0b035) ([#2915](https://github.com/tauri-apps/plugins-workspace/pull/2915) by [@samhinshaw](https://github.com/tauri-apps/plugins-workspace/../../samhinshaw)) `readFile` now returns a more specific type `Promise<Uint8Array<ArrayBuffer>>` instead of the default `Promise<Uint8Array<ArrayBufferLike>`
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
- [`44a1f659`](https://github.com/tauri-apps/plugins-workspace/commit/44a1f659125a341191420e650608b0b6ff316a0e) ([#2846](https://github.com/tauri-apps/plugins-workspace/pull/2846) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `writeFile` doesn't create a new file by default when the data is a `ReadableStream`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.4.1"
|
||||
version = "2.4.2"
|
||||
description = "Access the file system."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -24,7 +24,7 @@ ios = { level = "partial", notes = "Access is restricted to Application folder b
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
toml = "0.8"
|
||||
toml = "0.9"
|
||||
tauri-utils = { workspace = true, features = ["build"] }
|
||||
|
||||
[dependencies]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -739,7 +739,7 @@ interface ReadFileOptions {
|
||||
async function readFile(
|
||||
path: string | URL,
|
||||
options?: ReadFileOptions
|
||||
): Promise<Uint8Array> {
|
||||
): Promise<Uint8Array<ArrayBuffer>> {
|
||||
if (path instanceof URL && path.protocol !== 'file:') {
|
||||
throw new TypeError('Must be a file URL.')
|
||||
}
|
||||
@@ -1074,7 +1074,12 @@ async function writeFile(
|
||||
}
|
||||
|
||||
if (data instanceof ReadableStream) {
|
||||
const file = await open(path, { create: true, ...options })
|
||||
const file = await open(path, {
|
||||
read: false,
|
||||
create: true,
|
||||
write: true,
|
||||
...options
|
||||
})
|
||||
const reader = data.getReader()
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-fs",
|
||||
"version": "2.4.1",
|
||||
"version": "2.4.2",
|
||||
"description": "Access the file system.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3748,6 +3748,28 @@ This enables all index or metadata related commands without any pre-configured a
|
||||
|
||||
An empty permission you can use to modify the global scope.
|
||||
|
||||
## Example
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": "read-documents",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"fs:allow-read",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [
|
||||
"$APPDATA/documents/**/*"
|
||||
],
|
||||
"deny": [
|
||||
"$APPDATA/documents/secret.txt"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -2005,10 +2005,10 @@
|
||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||
},
|
||||
{
|
||||
"description": "An empty permission you can use to modify the global scope.",
|
||||
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
||||
"type": "string",
|
||||
"const": "scope",
|
||||
"markdownDescription": "An empty permission you can use to modify the global scope."
|
||||
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
||||
},
|
||||
{
|
||||
"description": "This enables all write related commands without any pre-configured accessible paths.",
|
||||
|
||||
@@ -2,4 +2,27 @@
|
||||
|
||||
[[permission]]
|
||||
identifier = "scope"
|
||||
description = "An empty permission you can use to modify the global scope."
|
||||
description = """
|
||||
An empty permission you can use to modify the global scope.
|
||||
|
||||
## Example
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": "read-documents",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"fs:allow-read",
|
||||
{
|
||||
"identifier": "fs:scope",
|
||||
"allow": [
|
||||
"$APPDATA/documents/**/*"
|
||||
],
|
||||
"deny": [
|
||||
"$APPDATA/documents/secret.txt"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
+110
-18
@@ -85,6 +85,7 @@ pub fn create<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<ResourceId> {
|
||||
let resolved_path = resolve_path(
|
||||
"create",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -119,6 +120,7 @@ pub fn open<R: Runtime>(
|
||||
options: Option<OpenOptions>,
|
||||
) -> CommandResult<ResourceId> {
|
||||
let (file, _path) = resolve_file(
|
||||
"open",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -167,6 +169,7 @@ pub async fn copy_file<R: Runtime>(
|
||||
options: Option<CopyFileOptions>,
|
||||
) -> CommandResult<()> {
|
||||
let resolved_from_path = resolve_path(
|
||||
"copy-file",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -174,6 +177,7 @@ pub async fn copy_file<R: Runtime>(
|
||||
options.as_ref().and_then(|o| o.from_path_base_dir),
|
||||
)?;
|
||||
let resolved_to_path = resolve_path(
|
||||
"copy-file",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -208,6 +212,7 @@ pub fn mkdir<R: Runtime>(
|
||||
options: Option<MkdirOptions>,
|
||||
) -> CommandResult<()> {
|
||||
let resolved_path = resolve_path(
|
||||
"mkdir",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -255,6 +260,7 @@ pub async fn read_dir<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<Vec<DirEntry>> {
|
||||
let resolved_path = resolve_path(
|
||||
"read-dir",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -331,8 +337,8 @@ pub async fn read<R: Runtime>(
|
||||
Ok(tauri::ipc::Response::new(data))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn read_file<R: Runtime>(
|
||||
async fn read_file_inner<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: Webview<R>,
|
||||
global_scope: GlobalScope<Entry>,
|
||||
command_scope: CommandScope<Entry>,
|
||||
@@ -340,6 +346,7 @@ pub async fn read_file<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<tauri::ipc::Response> {
|
||||
let (mut file, path) = resolve_file(
|
||||
permission,
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -367,6 +374,25 @@ pub async fn read_file<R: Runtime>(
|
||||
Ok(tauri::ipc::Response::new(contents))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn read_file<R: Runtime>(
|
||||
webview: Webview<R>,
|
||||
global_scope: GlobalScope<Entry>,
|
||||
command_scope: CommandScope<Entry>,
|
||||
path: SafeFilePath,
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<tauri::ipc::Response> {
|
||||
read_file_inner(
|
||||
"read-file",
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
path,
|
||||
options,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
// TODO, remove in v3, rely on `read_file` command instead
|
||||
#[tauri::command]
|
||||
pub async fn read_text_file<R: Runtime>(
|
||||
@@ -376,7 +402,15 @@ pub async fn read_text_file<R: Runtime>(
|
||||
path: SafeFilePath,
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<tauri::ipc::Response> {
|
||||
read_file(webview, global_scope, command_scope, path, options).await
|
||||
read_file_inner(
|
||||
"read-text-file",
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
path,
|
||||
options,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -388,6 +422,7 @@ pub fn read_text_file_lines<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<ResourceId> {
|
||||
let resolved_path = resolve_path(
|
||||
"read-text-file-lines",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -452,6 +487,7 @@ pub fn remove<R: Runtime>(
|
||||
options: Option<RemoveOptions>,
|
||||
) -> CommandResult<()> {
|
||||
let resolved_path = resolve_path(
|
||||
"remove",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -521,6 +557,7 @@ pub fn rename<R: Runtime>(
|
||||
options: Option<RenameOptions>,
|
||||
) -> CommandResult<()> {
|
||||
let resolved_old_path = resolve_path(
|
||||
"rename",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -528,6 +565,7 @@ pub fn rename<R: Runtime>(
|
||||
options.as_ref().and_then(|o| o.old_path_base_dir),
|
||||
)?;
|
||||
let resolved_new_path = resolve_path(
|
||||
"rename",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -575,6 +613,7 @@ pub async fn seek<R: Runtime>(
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||
permission: &str,
|
||||
metadata_fn: F,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
@@ -585,6 +624,7 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
||||
match path {
|
||||
SafeFilePath::Url(url) => {
|
||||
let (file, path) = resolve_file(
|
||||
permission,
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
@@ -606,6 +646,7 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
||||
})
|
||||
}
|
||||
SafeFilePath::Path(p) => get_fs_metadata(
|
||||
permission,
|
||||
metadata_fn,
|
||||
webview,
|
||||
global_scope,
|
||||
@@ -618,6 +659,7 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||
permission: &str,
|
||||
metadata_fn: F,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
@@ -626,6 +668,7 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<std::fs::Metadata> {
|
||||
get_fs_metadata(
|
||||
permission,
|
||||
metadata_fn,
|
||||
webview,
|
||||
global_scope,
|
||||
@@ -636,6 +679,7 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
||||
}
|
||||
|
||||
fn get_fs_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||
permission: &str,
|
||||
metadata_fn: F,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
@@ -644,6 +688,7 @@ fn get_fs_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::M
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<std::fs::Metadata> {
|
||||
let resolved_path = resolve_path(
|
||||
permission,
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
@@ -668,6 +713,7 @@ pub fn stat<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<FileInfo> {
|
||||
let metadata = get_metadata(
|
||||
"stat",
|
||||
|p| std::fs::metadata(p),
|
||||
&webview,
|
||||
&global_scope,
|
||||
@@ -688,6 +734,7 @@ pub fn lstat<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<FileInfo> {
|
||||
let metadata = get_metadata(
|
||||
"lstat",
|
||||
|p| std::fs::symlink_metadata(p),
|
||||
&webview,
|
||||
&global_scope,
|
||||
@@ -716,6 +763,7 @@ pub async fn truncate<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<()> {
|
||||
let resolved_path = resolve_path(
|
||||
"truncate",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -784,23 +832,13 @@ fn default_create_value() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn write_file<R: Runtime>(
|
||||
async fn write_file_inner<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: Webview<R>,
|
||||
global_scope: GlobalScope<Entry>,
|
||||
command_scope: CommandScope<Entry>,
|
||||
request: tauri::ipc::Request<'_>,
|
||||
) -> CommandResult<()> {
|
||||
let data = match request.body() {
|
||||
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
|
||||
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
|
||||
data.iter()
|
||||
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
|
||||
.collect(),
|
||||
),
|
||||
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
|
||||
};
|
||||
|
||||
let path = request
|
||||
.headers()
|
||||
.get("path")
|
||||
@@ -811,6 +849,7 @@ pub async fn write_file<R: Runtime>(
|
||||
.map_err(|_| anyhow::anyhow!("path is not a valid UTF-8").into())
|
||||
})
|
||||
.and_then(|p| SafeFilePath::from_str(&p).map_err(CommandError::from))?;
|
||||
|
||||
let options: Option<WriteFileOptions> = request
|
||||
.headers()
|
||||
.get("options")
|
||||
@@ -818,6 +857,7 @@ pub async fn write_file<R: Runtime>(
|
||||
.and_then(|opts| serde_json::from_str(opts).ok());
|
||||
|
||||
let (mut file, path) = resolve_file(
|
||||
permission,
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -853,6 +893,16 @@ pub async fn write_file<R: Runtime>(
|
||||
},
|
||||
)?;
|
||||
|
||||
let data = match request.body() {
|
||||
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
|
||||
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
|
||||
data.iter()
|
||||
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
|
||||
.collect(),
|
||||
),
|
||||
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
|
||||
};
|
||||
|
||||
file.write_all(&data)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
@@ -863,6 +913,16 @@ pub async fn write_file<R: Runtime>(
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn write_file<R: Runtime>(
|
||||
webview: Webview<R>,
|
||||
global_scope: GlobalScope<Entry>,
|
||||
command_scope: CommandScope<Entry>,
|
||||
request: tauri::ipc::Request<'_>,
|
||||
) -> CommandResult<()> {
|
||||
write_file_inner("write-file", webview, global_scope, command_scope, request).await
|
||||
}
|
||||
|
||||
// TODO, remove in v3, rely on `write_file` command instead
|
||||
#[tauri::command]
|
||||
pub async fn write_text_file<R: Runtime>(
|
||||
@@ -871,7 +931,14 @@ pub async fn write_text_file<R: Runtime>(
|
||||
command_scope: CommandScope<Entry>,
|
||||
request: tauri::ipc::Request<'_>,
|
||||
) -> CommandResult<()> {
|
||||
write_file(webview, global_scope, command_scope, request).await
|
||||
write_file_inner(
|
||||
"write-text-file",
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
request,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -883,6 +950,7 @@ pub fn exists<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<bool> {
|
||||
let resolved_path = resolve_path(
|
||||
"exists",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -901,6 +969,7 @@ pub async fn size<R: Runtime>(
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<u64> {
|
||||
let resolved_path = resolve_path(
|
||||
"size",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
@@ -943,16 +1012,25 @@ fn get_dir_size(path: &PathBuf) -> CommandResult<u64> {
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn resolve_file<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
command_scope: &CommandScope<Entry>,
|
||||
path: SafeFilePath,
|
||||
open_options: OpenOptions,
|
||||
) -> CommandResult<(File, PathBuf)> {
|
||||
resolve_file_in_fs(webview, global_scope, command_scope, path, open_options)
|
||||
resolve_file_in_fs(
|
||||
permission,
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
path,
|
||||
open_options,
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_file_in_fs<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
command_scope: &CommandScope<Entry>,
|
||||
@@ -960,6 +1038,7 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
open_options: OpenOptions,
|
||||
) -> CommandResult<(File, PathBuf)> {
|
||||
let path = resolve_path(
|
||||
permission,
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
@@ -980,6 +1059,7 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn resolve_file<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
command_scope: &CommandScope<Entry>,
|
||||
@@ -997,6 +1077,7 @@ pub fn resolve_file<R: Runtime>(
|
||||
Ok((file, path))
|
||||
}
|
||||
SafeFilePath::Path(path) => resolve_file_in_fs(
|
||||
permission,
|
||||
webview,
|
||||
global_scope,
|
||||
command_scope,
|
||||
@@ -1007,6 +1088,7 @@ pub fn resolve_file<R: Runtime>(
|
||||
}
|
||||
|
||||
pub fn resolve_path<R: Runtime>(
|
||||
permission: &str,
|
||||
webview: &Webview<R>,
|
||||
global_scope: &GlobalScope<Entry>,
|
||||
command_scope: &CommandScope<Entry>,
|
||||
@@ -1052,7 +1134,17 @@ pub fn resolve_path<R: Runtime>(
|
||||
if fs_scope.scope.is_allowed(&path) || scope.is_allowed(&path) {
|
||||
Ok(path)
|
||||
} else {
|
||||
Err(CommandError::Plugin(Error::PathForbidden(path)))
|
||||
#[cfg(not(debug_assertions))]
|
||||
return Err(CommandError::Plugin(Error::PathForbidden(path)));
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
Err(
|
||||
anyhow::anyhow!(
|
||||
"forbidden path: {}, maybe it is not allowed on the scope for `allow-{permission}` permission in your capability file",
|
||||
path.display()
|
||||
)
|
||||
)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ impl<R: Runtime> Fs<R> {
|
||||
std::fs::File::from_raw_fd(fd)
|
||||
})
|
||||
} else {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ pub fn watch<R: Runtime>(
|
||||
.into_iter()
|
||||
.map(|path| {
|
||||
resolve_path(
|
||||
"watch",
|
||||
&webview,
|
||||
&global_scope,
|
||||
&command_scope,
|
||||
|
||||
@@ -91,11 +91,9 @@ public class Geolocation(private val context: Context) {
|
||||
val lowPrio = if (networkEnabled) Priority.PRIORITY_BALANCED_POWER_ACCURACY else Priority.PRIORITY_LOW_POWER
|
||||
val prio = if (enableHighAccuracy) Priority.PRIORITY_HIGH_ACCURACY else lowPrio
|
||||
|
||||
Logger.error(prio.toString())
|
||||
|
||||
val locationRequest = LocationRequest.Builder(10000)
|
||||
val locationRequest = LocationRequest.Builder(timeout)
|
||||
.setMaxUpdateDelayMillis(timeout)
|
||||
.setMinUpdateIntervalMillis(5000)
|
||||
.setMinUpdateIntervalMillis(timeout)
|
||||
.setPriority(prio)
|
||||
.build()
|
||||
|
||||
@@ -145,4 +143,4 @@ public class Geolocation(private val context: Context) {
|
||||
|
||||
return lastLoc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.5.2]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.2`
|
||||
|
||||
## \[2.5.1]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.5.1"
|
||||
version = "2.5.2"
|
||||
description = "Access an HTTP client written in Rust."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -34,7 +34,7 @@ serde_json = { workspace = true }
|
||||
tauri = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { version = "1", features = ["sync", "macros"] }
|
||||
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
|
||||
tauri-plugin-fs = { path = "../fs", version = "2.4.2" }
|
||||
urlpattern = "0.3"
|
||||
regex = "1"
|
||||
http = "1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-http",
|
||||
"version": "2.5.1",
|
||||
"version": "2.5.2",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.7.0]
|
||||
|
||||
- [`625bb1c0`](https://github.com/tauri-apps/plugins-workspace/commit/625bb1c0965394b88522643731f78ccbcca84add) ([#2965](https://github.com/tauri-apps/plugins-workspace/pull/2965) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Re-export the log crate.
|
||||
|
||||
## \[2.6.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
description = "Configurable logging for your Tauri app."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-log",
|
||||
"version": "2.6.0",
|
||||
"version": "2.7.0",
|
||||
"description": "Configurable logging for your Tauri app.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use log::RecordBuilder;
|
||||
|
||||
use crate::{LogLevel, WEBVIEW_TARGET};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn log(
|
||||
level: LogLevel,
|
||||
message: String,
|
||||
location: Option<&str>,
|
||||
file: Option<&str>,
|
||||
line: Option<u32>,
|
||||
key_values: Option<HashMap<String, String>>,
|
||||
) {
|
||||
let level = log::Level::from(level);
|
||||
|
||||
let target = if let Some(location) = location {
|
||||
format!("{WEBVIEW_TARGET}:{location}")
|
||||
} else {
|
||||
WEBVIEW_TARGET.to_string()
|
||||
};
|
||||
|
||||
let mut builder = RecordBuilder::new();
|
||||
builder.level(level).target(&target).file(file).line(line);
|
||||
|
||||
let key_values = key_values.unwrap_or_default();
|
||||
let mut kv = HashMap::new();
|
||||
for (k, v) in key_values.iter() {
|
||||
kv.insert(k.as_str(), v.as_str());
|
||||
}
|
||||
builder.key_values(&kv);
|
||||
#[cfg(feature = "tracing")]
|
||||
emit_trace(level, &message, location, file, line, &kv);
|
||||
|
||||
log::logger().log(&builder.args(format_args!("{message}")).build());
|
||||
}
|
||||
|
||||
// Target becomes default and location is added as a parameter
|
||||
#[cfg(feature = "tracing")]
|
||||
fn emit_trace(
|
||||
level: log::Level,
|
||||
message: &String,
|
||||
location: Option<&str>,
|
||||
file: Option<&str>,
|
||||
line: Option<u32>,
|
||||
kv: &HashMap<&str, &str>,
|
||||
) {
|
||||
macro_rules! emit_event {
|
||||
($level:expr) => {
|
||||
tracing::event!(
|
||||
target: WEBVIEW_TARGET,
|
||||
$level,
|
||||
message = %message,
|
||||
location = location,
|
||||
file,
|
||||
line,
|
||||
?kv
|
||||
)
|
||||
};
|
||||
}
|
||||
match level {
|
||||
log::Level::Error => emit_event!(tracing::Level::ERROR),
|
||||
log::Level::Warn => emit_event!(tracing::Level::WARN),
|
||||
log::Level::Info => emit_event!(tracing::Level::INFO),
|
||||
log::Level::Debug => emit_event!(tracing::Level::DEBUG),
|
||||
log::Level::Trace => emit_event!(tracing::Level::TRACE),
|
||||
}
|
||||
}
|
||||
+4
-67
@@ -10,12 +10,10 @@
|
||||
)]
|
||||
|
||||
use fern::{Filter, FormatCallback};
|
||||
use log::{logger, RecordBuilder};
|
||||
use log::{LevelFilter, Record};
|
||||
use serde::Serialize;
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
fmt::Arguments,
|
||||
fs::{self, File},
|
||||
@@ -30,6 +28,9 @@ use tauri::{AppHandle, Emitter};
|
||||
use time::{macros::format_description, OffsetDateTime};
|
||||
|
||||
pub use fern;
|
||||
pub use log;
|
||||
|
||||
mod commands;
|
||||
|
||||
pub const WEBVIEW_TARGET: &str = "webview";
|
||||
|
||||
@@ -206,70 +207,6 @@ impl Target {
|
||||
}
|
||||
}
|
||||
|
||||
// Target becomes default and location is added as a parameter
|
||||
#[cfg(feature = "tracing")]
|
||||
fn emit_trace(
|
||||
level: log::Level,
|
||||
message: &String,
|
||||
location: Option<&str>,
|
||||
file: Option<&str>,
|
||||
line: Option<u32>,
|
||||
kv: &HashMap<&str, &str>,
|
||||
) {
|
||||
macro_rules! emit_event {
|
||||
($level:expr) => {
|
||||
tracing::event!(
|
||||
target: WEBVIEW_TARGET,
|
||||
$level,
|
||||
message = %message,
|
||||
location = location,
|
||||
file,
|
||||
line,
|
||||
?kv
|
||||
)
|
||||
};
|
||||
}
|
||||
match level {
|
||||
log::Level::Error => emit_event!(tracing::Level::ERROR),
|
||||
log::Level::Warn => emit_event!(tracing::Level::WARN),
|
||||
log::Level::Info => emit_event!(tracing::Level::INFO),
|
||||
log::Level::Debug => emit_event!(tracing::Level::DEBUG),
|
||||
log::Level::Trace => emit_event!(tracing::Level::TRACE),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn log(
|
||||
level: LogLevel,
|
||||
message: String,
|
||||
location: Option<&str>,
|
||||
file: Option<&str>,
|
||||
line: Option<u32>,
|
||||
key_values: Option<HashMap<String, String>>,
|
||||
) {
|
||||
let level = log::Level::from(level);
|
||||
|
||||
let target = if let Some(location) = location {
|
||||
format!("{WEBVIEW_TARGET}:{location}")
|
||||
} else {
|
||||
WEBVIEW_TARGET.to_string()
|
||||
};
|
||||
|
||||
let mut builder = RecordBuilder::new();
|
||||
builder.level(level).target(&target).file(file).line(line);
|
||||
|
||||
let key_values = key_values.unwrap_or_default();
|
||||
let mut kv = HashMap::new();
|
||||
for (k, v) in key_values.iter() {
|
||||
kv.insert(k.as_str(), v.as_str());
|
||||
}
|
||||
builder.key_values(&kv);
|
||||
#[cfg(feature = "tracing")]
|
||||
emit_trace(level, &message, location, file, line, &kv);
|
||||
|
||||
logger().log(&builder.args(format_args!("{message}")).build());
|
||||
}
|
||||
|
||||
pub struct Builder {
|
||||
dispatch: fern::Dispatch,
|
||||
rotation_strategy: RotationStrategy,
|
||||
@@ -528,7 +465,7 @@ impl Builder {
|
||||
}
|
||||
|
||||
fn plugin_builder<R: Runtime>() -> plugin::Builder<R> {
|
||||
plugin::Builder::new("log").invoke_handler(tauri::generate_handler![log])
|
||||
plugin::Builder::new("log").invoke_handler(tauri::generate_handler![commands::log])
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`fe23a5e0`](https://github.com/tauri-apps/plugins-workspace/commit/fe23a5e01399a6ad61426bf8a94a6bb97227cf88) ([#2885](https://github.com/tauri-apps/plugins-workspace/pull/2885) by [@zaphim12](https://github.com/tauri-apps/plugins-workspace/../../zaphim12)) On iOS, the reader session will now get closed properly on errors, preventing dangling invalid sessions that could prevent subsequent write attempts.
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-nfc"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
description = "Read and write NFC tags on Android and iOS."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-nfc",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.1",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`8abb31ee`](https://github.com/tauri-apps/plugins-workspace/commit/8abb31ee59c68197102c0aa699d690b34646ec3c) ([#2905](https://github.com/tauri-apps/plugins-workspace/pull/2905) by [@ChristianPavilonis](https://github.com/tauri-apps/plugins-workspace/../../ChristianPavilonis)) Fix notification scheduling on iOS.
|
||||
- [`2d03e2ea`](https://github.com/tauri-apps/plugins-workspace/commit/2d03e2eac2c19ad997d81d23836ab6a219252ffb) ([#2678](https://github.com/tauri-apps/plugins-workspace/pull/2678) by [@Keerthi421](https://github.com/tauri-apps/plugins-workspace/../../Keerthi421)) Added sound support for desktop notifications which was previously only available on mobile platforms.
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-notification"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
description = "Send desktop and mobile notifications on your Tauri application."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -95,6 +95,45 @@ export async function enqueueNotification(title, body) {
|
||||
}
|
||||
```
|
||||
|
||||
### Notification with Sound
|
||||
|
||||
You can add sound to your notifications on all platforms (desktop and mobile):
|
||||
|
||||
```javascript
|
||||
import { sendNotification } from '@tauri-apps/plugin-notification'
|
||||
import { platform } from '@tauri-apps/api/os'
|
||||
|
||||
// Basic notification with sound
|
||||
sendNotification({
|
||||
title: 'New Message',
|
||||
body: 'You have a new message',
|
||||
sound: 'notification.wav' // Path to sound file
|
||||
})
|
||||
|
||||
// Platform-specific sounds
|
||||
async function sendPlatformSpecificNotification() {
|
||||
const platformName = platform()
|
||||
|
||||
let soundPath
|
||||
if (platformName === 'darwin') {
|
||||
// On macOS: use system sounds or sound files in the app bundle
|
||||
soundPath = 'Ping' // macOS system sound
|
||||
} else if (platformName === 'linux') {
|
||||
// On Linux: use XDG theme sounds or file paths
|
||||
soundPath = 'message-new-instant' // XDG theme sound
|
||||
} else {
|
||||
// On Windows: use file paths
|
||||
soundPath = 'notification.wav'
|
||||
}
|
||||
|
||||
sendNotification({
|
||||
title: 'Platform-specific Notification',
|
||||
body: 'This notification uses platform-specific sound',
|
||||
sound: soundPath
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
|
||||
|
||||
@@ -71,7 +71,13 @@ interface Options {
|
||||
*/
|
||||
groupSummary?: boolean
|
||||
/**
|
||||
* The sound resource name. Only available on mobile.
|
||||
* The sound resource name or file path for the notification.
|
||||
*
|
||||
* Platform specific behavior:
|
||||
* - On macOS: use system sounds (e.g., "Ping", "Blow") or sound files in the app bundle
|
||||
* - On Linux: use XDG theme sounds (e.g., "message-new-instant") or file paths
|
||||
* - On Windows: use file paths to sound files (.wav format)
|
||||
* - On Mobile: use resource names
|
||||
*/
|
||||
sound?: string
|
||||
/**
|
||||
|
||||
@@ -38,10 +38,17 @@ func makeNotificationContent(_ notification: Notification) throws -> UNNotificat
|
||||
arguments: nil)
|
||||
}
|
||||
|
||||
content.userInfo = [
|
||||
"__EXTRA__": notification.extra as Any,
|
||||
"__SCHEDULE__": notification.schedule as Any,
|
||||
]
|
||||
var userInfo: [String: Any] = [:]
|
||||
|
||||
if let extra = notification.extra {
|
||||
userInfo["__EXTRA__"] = extra
|
||||
}
|
||||
|
||||
if let schedule = notification.schedule {
|
||||
userInfo["__SCHEDULE__"] = scheduleToDictionary(schedule)
|
||||
}
|
||||
|
||||
content.userInfo = userInfo
|
||||
|
||||
if let actionTypeId = notification.actionTypeId {
|
||||
content.categoryIdentifier = actionTypeId
|
||||
@@ -66,6 +73,56 @@ func makeNotificationContent(_ notification: Notification) throws -> UNNotificat
|
||||
return content
|
||||
}
|
||||
|
||||
func scheduleToDictionary(_ schedule: NotificationSchedule) -> [String: Any] {
|
||||
switch schedule {
|
||||
case .at(let date, let repeating):
|
||||
return [
|
||||
"type": "at",
|
||||
"date": date,
|
||||
"repeating": repeating
|
||||
]
|
||||
case .interval(let interval):
|
||||
return [
|
||||
"type": "interval",
|
||||
"interval": scheduleIntervalToDictionary(interval)
|
||||
]
|
||||
case .every(let interval, let count):
|
||||
return [
|
||||
"type": "every",
|
||||
"interval": interval.rawValue,
|
||||
"count": count
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
func scheduleIntervalToDictionary(_ interval: ScheduleInterval) -> [String: Any] {
|
||||
var dict: [String: Any] = [:]
|
||||
|
||||
if let year = interval.year {
|
||||
dict["year"] = year
|
||||
}
|
||||
if let month = interval.month {
|
||||
dict["month"] = month
|
||||
}
|
||||
if let day = interval.day {
|
||||
dict["day"] = day
|
||||
}
|
||||
if let weekday = interval.weekday {
|
||||
dict["weekday"] = weekday
|
||||
}
|
||||
if let hour = interval.hour {
|
||||
dict["hour"] = hour
|
||||
}
|
||||
if let minute = interval.minute {
|
||||
dict["minute"] = minute
|
||||
}
|
||||
if let second = interval.second {
|
||||
dict["second"] = second
|
||||
}
|
||||
|
||||
return dict
|
||||
}
|
||||
|
||||
func makeAttachments(_ attachments: [NotificationAttachment]) throws -> [UNNotificationAttachment] {
|
||||
var createdAttachments = [UNNotificationAttachment]()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-notification",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.1",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ impl<R: Runtime> crate::NotificationBuilder<R> {
|
||||
if let Some(icon) = self.data.icon {
|
||||
notification = notification.icon(icon);
|
||||
}
|
||||
if let Some(sound) = self.data.sound {
|
||||
notification = notification.sound(sound);
|
||||
}
|
||||
#[cfg(feature = "windows7-compat")]
|
||||
{
|
||||
notification.notify(&self.app)?;
|
||||
@@ -102,6 +105,8 @@ mod imp {
|
||||
title: Option<String>,
|
||||
/// The notification icon.
|
||||
icon: Option<String>,
|
||||
/// The notification sound.
|
||||
sound: Option<String>,
|
||||
/// The notification identifier
|
||||
identifier: String,
|
||||
}
|
||||
@@ -136,6 +141,13 @@ mod imp {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the notification sound file.
|
||||
#[must_use]
|
||||
pub fn sound(mut self, sound: impl Into<String>) -> Self {
|
||||
self.sound = Some(sound.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Shows the notification.
|
||||
///
|
||||
/// # Examples
|
||||
@@ -177,6 +189,9 @@ mod imp {
|
||||
} else {
|
||||
notification.auto_icon();
|
||||
}
|
||||
if let Some(sound) = self.sound {
|
||||
notification.sound_name(&sound);
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let exe = tauri::utils::platform::current_exe()?;
|
||||
@@ -250,6 +265,7 @@ mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the notification on Windows 7.
|
||||
#[cfg(all(windows, feature = "windows7-compat"))]
|
||||
fn notify_win7<R: tauri::Runtime>(self, app: &tauri::AppHandle<R>) -> crate::Result<()> {
|
||||
let app_ = app.clone();
|
||||
|
||||
@@ -132,7 +132,7 @@ impl<R: Runtime> NotificationBuilder<R> {
|
||||
self
|
||||
}
|
||||
|
||||
/// The sound resource name. Only available on mobile.
|
||||
/// The sound resource name for the notification.
|
||||
pub fn sound(mut self, sound: impl Into<String>) -> Self {
|
||||
self.data.sound.replace(sound.into());
|
||||
self
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.5.0]
|
||||
|
||||
### enhance
|
||||
|
||||
- [`b8056f48`](https://github.com/tauri-apps/plugins-workspace/commit/b8056f484c7144af095d4d6ded1e8adbb9b8a865) ([#2897](https://github.com/tauri-apps/plugins-workspace/pull/2897) by [@petersamokhin](https://github.com/tauri-apps/plugins-workspace/../../petersamokhin)) Allow reveal multiple items in the file explorer.
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
description = "Open files and URLs using their default application."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -35,8 +35,6 @@ tauri = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
open = { version = "5", features = ["shellexecute-on-windows"] }
|
||||
glob = { workspace = true }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
dunce = { workspace = true }
|
||||
|
||||
[target."cfg(windows)".dependencies.windows]
|
||||
|
||||
@@ -75,6 +75,10 @@ await openPath('/path/to/file', 'firefox')
|
||||
|
||||
// Reveal a path with the system's default explorer
|
||||
await revealItemInDir('/path/to/file')
|
||||
|
||||
// Reveal multiple paths with the system's default explorer
|
||||
// Note: will be renamed to `revealItemsInDir` in the next major version
|
||||
await revealItemInDir(['/path/to/file', '/path/to/another/file'])
|
||||
```
|
||||
|
||||
### Usage from Rust
|
||||
@@ -102,6 +106,9 @@ fn main() {
|
||||
|
||||
// Reveal a path with the system's default explorer
|
||||
opener.reveal_item_in_dir("/path/to/file")?;
|
||||
|
||||
// Reveal multiple paths with the system's default explorer
|
||||
opener.reveal_items_in_dir(["/path/to/file"])?;
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user