mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-22 17:10:53 +02:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b7d59ca27 | |||
| ab7489c964 | |||
| 3fb27bf13a | |||
| 7e45774610 | |||
| 526726162f | |||
| 03afae6d72 | |||
| 57ac986453 | |||
| 2ed6d6c1de | |||
| cdfd462955 | |||
| d6e0b6bbb1 | |||
| 40ae0a7fa0 | |||
| edc52ea056 | |||
| a0d949d93e | |||
| 13c63af965 | |||
| cad301fcc1 | |||
| 254f222e0e | |||
| b1439be667 | |||
| d157387722 | |||
| 41f6274270 | |||
| f08980f123 | |||
| 78df86f810 | |||
| aecec42d5d | |||
| 0767dcbd5c | |||
| 4be7690085 | |||
| c2b3981248 | |||
| 0c23b8ecfe | |||
| 4350ca652d | |||
| 1953f00188 | |||
| 9883f396dc | |||
| d8645ab3e5 | |||
| cb863d57c6 | |||
| d67e4f8cdc | |||
| e571e0be9d | |||
| 83ac944abf | |||
| 0139c54d0e | |||
| cad34b73fa | |||
| c0d64bf7d9 | |||
| e919bab3eb | |||
| 95c9291cee | |||
| 114e902537 | |||
| 6972acdca6 | |||
| 8bbc7a0d1d | |||
| 2d013294ef |
@@ -1,7 +1,17 @@
|
||||
[advisories]
|
||||
ignore = [
|
||||
# rsa Marvin Attack
|
||||
"RUSTSEC-2023-0071",
|
||||
# time crate can't be updated in the repo because of MSRV, users are unaffected
|
||||
"RUSTSEC-2026-0009",
|
||||
# libflate crates can't be updated in the repo because of MSRV, users are unaffected
|
||||
"RUSTSEC-2026-0105",
|
||||
# quick-xml, need an update in plist, can't be updated in the repo because of MSRV, users are unaffected
|
||||
# Also needs on update in wayland-scanner > arboard > tauri-plugin-clipboard-manager
|
||||
"RUSTSEC-2026-0194",
|
||||
# quick-xml, need an update in plist, can't be updated in the repo because of MSRV, users are unaffected
|
||||
# Also needs on update in wayland-scanner > arboard > tauri-plugin-clipboard-manager
|
||||
"RUSTSEC-2026-0195",
|
||||
# quinn-proto, can't be updated in the repo because of MSRV, users are unaffected
|
||||
"RUSTSEC-2026-0185",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"deep-link": patch
|
||||
"deep-link-js": patch
|
||||
---
|
||||
|
||||
adds proper Platform-specific sections to the docs for `register`, `unregister`, `isRegistered`, and `onOpenUrl`
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"fs": patch
|
||||
"fs-js": patch
|
||||
---
|
||||
|
||||
Fixed `deny-webview-data` has no effect
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
nfc: patch
|
||||
nfc-js: patch
|
||||
---
|
||||
|
||||
Expect a `NFCTag` as input and return a `ScanResponse` in the `scan` function.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"updater": minor
|
||||
"updater-js": minor
|
||||
---
|
||||
|
||||
On Windows, add a new option `restartAfterInstall`/`restart_after_install` to install an update without the installer re-launching the app
|
||||
@@ -33,20 +33,19 @@ jobs:
|
||||
audit-js:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
- name: audit
|
||||
run: pnpm audit
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
audit-rust:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- uses: rustsec/audit-check@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: check change files end with .md
|
||||
run: |
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
outputs:
|
||||
packages: ${{ steps.filter.outputs.changes }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
@@ -153,21 +153,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
|
||||
- name: build api
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # required for use of git history
|
||||
- name: covector status
|
||||
|
||||
@@ -28,18 +28,17 @@ jobs:
|
||||
successfulPublish: ${{ steps.covector.outputs.successfulPublish }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0 # required for use of git history
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
|
||||
- name: cargo login
|
||||
@@ -74,7 +73,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request With Versions Bumped
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # 7.0.7
|
||||
uses: peter-evans/create-pull-request@v8.1.1
|
||||
if: steps.covector.outputs.commandRan == 'version'
|
||||
with:
|
||||
title: 'Publish New Versions (${{ github.ref_name }})'
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: install Rust stable and rustfmt
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@@ -25,20 +25,19 @@ jobs:
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
- run: pnpm format:check
|
||||
|
||||
@@ -46,7 +45,7 @@ jobs:
|
||||
name: taplo (.toml files)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
platform: [ubuntu-22.04, macos-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -36,20 +36,19 @@ jobs:
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
- name: eslint
|
||||
run: pnpm lint
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
outputs:
|
||||
packages: ${{ steps.filter.outputs.changes }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
package: ${{ fromJSON(needs.changes.outputs.packages) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: install webkit2gtk
|
||||
run: |
|
||||
|
||||
@@ -19,26 +19,25 @@ jobs:
|
||||
sync-to-mirrors:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Fetch git tags
|
||||
run: git fetch origin 'refs/tags/*:refs/tags/*'
|
||||
|
||||
- name: Cache pnpm modules
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.pnpm-store
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
with:
|
||||
version: 10.x.x
|
||||
run_install: true
|
||||
|
||||
- name: Build packages
|
||||
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
outputs:
|
||||
packages: ${{ steps.filter.outputs.changes }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
@@ -225,7 +225,7 @@ jobs:
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: install webkit2gtk
|
||||
if: contains(matrix.platform.target, 'unknown-linux')
|
||||
|
||||
Generated
+214
-175
@@ -201,13 +201,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
|
||||
[[package]]
|
||||
name = "api"
|
||||
version = "2.0.43"
|
||||
version = "2.0.46"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -300,7 +300,7 @@ dependencies = [
|
||||
"objc2-foundation 0.3.0",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
"wl-clipboard-rs",
|
||||
"x11rb",
|
||||
]
|
||||
@@ -332,7 +332,7 @@ dependencies = [
|
||||
"enumflags2",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
@@ -772,17 +772,6 @@ version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byte-unit"
|
||||
version = "5.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174"
|
||||
dependencies = [
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"utf8-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
version = "0.6.12"
|
||||
@@ -983,7 +972,7 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1052,7 +1041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1308,7 +1297,7 @@ dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa",
|
||||
"phf 0.13.1",
|
||||
"phf",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
@@ -1873,7 +1862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2470,9 +2459,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "global-hotkey"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7"
|
||||
checksum = "8c386b0a4a70cb2d39fffd74480f985b6f0bfbcb934b6a6b6b7e630e448f242e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"keyboard-types",
|
||||
@@ -2812,7 +2801,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"windows-registry",
|
||||
"windows-registry 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2827,7 +2816,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3093,7 +3082,7 @@ dependencies = [
|
||||
"iterator-sorted",
|
||||
"k256",
|
||||
"pbkdf2",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"scrypt",
|
||||
"serde",
|
||||
"sha2",
|
||||
@@ -3474,9 +3463,6 @@ name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
dependencies = [
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
@@ -3607,7 +3593,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
@@ -3784,7 +3770,7 @@ dependencies = [
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"smallvec",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4351,24 +4337,14 @@ dependencies = [
|
||||
"indexmap 2.11.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||
dependencies = [
|
||||
"phf_macros 0.11.3",
|
||||
"phf_shared 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
|
||||
dependencies = [
|
||||
"phf_macros 0.13.1",
|
||||
"phf_shared 0.13.1",
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -4378,18 +4354,8 @@ version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
|
||||
dependencies = [
|
||||
"phf_generator 0.13.1",
|
||||
"phf_shared 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||
dependencies = [
|
||||
"phf_shared 0.11.3",
|
||||
"rand 0.8.5",
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4399,20 +4365,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"phf_shared 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||
dependencies = [
|
||||
"phf_generator 0.11.3",
|
||||
"phf_shared 0.11.3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4421,22 +4374,13 @@ version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
|
||||
dependencies = [
|
||||
"phf_generator 0.13.1",
|
||||
"phf_shared 0.13.1",
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.13.1"
|
||||
@@ -4750,7 +4694,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.2",
|
||||
"lru-slab",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
@@ -4773,7 +4717,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4799,9 +4743,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
@@ -4810,9 +4754,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ec095654a25171c2124e9e3393a930bddbffdc939556c914957a4c3e0a87166"
|
||||
checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
@@ -5186,7 +5130,7 @@ dependencies = [
|
||||
"borsh",
|
||||
"bytes",
|
||||
"num-traits",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"rkyv",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5223,7 +5167,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5481,7 +5425,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"log",
|
||||
"new_debug_unreachable",
|
||||
"phf 0.13.1",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
"precomputed-hash",
|
||||
"rustc-hash",
|
||||
@@ -5995,7 +5939,7 @@ dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"rsa",
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
@@ -6036,7 +5980,7 @@ dependencies = [
|
||||
"md-5",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6097,7 +6041,7 @@ checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"parking_lot",
|
||||
"phf_shared 0.13.1",
|
||||
"phf_shared",
|
||||
"precomputed-hash",
|
||||
]
|
||||
|
||||
@@ -6107,8 +6051,8 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69"
|
||||
dependencies = [
|
||||
"phf_generator 0.13.1",
|
||||
"phf_shared 0.13.1",
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
@@ -6147,7 +6091,7 @@ dependencies = [
|
||||
"libsodium-sys-stable",
|
||||
"log",
|
||||
"nix 0.24.3",
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"windows 0.36.1",
|
||||
@@ -6160,7 +6104,7 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8300214898af5e153e7f66e49dbd1c6a21585f2d592d9f24f58b969792475ed6"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand 0.8.6",
|
||||
"stronghold-derive",
|
||||
]
|
||||
|
||||
@@ -6324,7 +6268,7 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"windows 0.61.1",
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
@@ -6348,9 +6292,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.45"
|
||||
version = "0.4.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
|
||||
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
@@ -6365,9 +6309,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.11.0"
|
||||
version = "2.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d059f2527558d9dba6f186dec4772610e1aecfd3f94002397613e7e648752b66"
|
||||
checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -6420,9 +6364,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.6.0"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be9aa8c59a894f76c29a002501c589de5eb4987a5913d62a6e0a47f320901988"
|
||||
checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@@ -6443,9 +6387,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.6.0"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3e4e8230d565106aa19dfbaa01a7ed01abf78047fe0577a83377224bd1bf20e"
|
||||
checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"ico",
|
||||
@@ -6469,9 +6413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.6.0"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc8de2cddbbc33dbdf4c84f170121886595efdbcc9cb4b3d76342b79d082cedc"
|
||||
checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -6511,7 +6455,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-barcode-scanner"
|
||||
version = "2.4.4"
|
||||
version = "2.4.5"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -6575,13 +6519,13 @@ dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"url",
|
||||
"windows-registry",
|
||||
"windows-result",
|
||||
"windows-registry 0.6.1",
|
||||
"windows-result 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.7.1"
|
||||
version = "2.7.2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"raw-window-handle",
|
||||
@@ -6634,7 +6578,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-global-shortcut"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
dependencies = [
|
||||
"global-hotkey",
|
||||
"log",
|
||||
@@ -6696,10 +6640,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"byte-unit",
|
||||
"fern",
|
||||
"log",
|
||||
"objc2 0.6.4",
|
||||
@@ -6734,7 +6677,7 @@ version = "2.3.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"notify-rust",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
@@ -6763,7 +6706,7 @@ dependencies = [
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"windows 0.61.1",
|
||||
"windows 0.62.2",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
@@ -6799,7 +6742,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-positioner"
|
||||
version = "2.3.1"
|
||||
version = "2.3.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -6839,7 +6782,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-single-instance"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -6847,8 +6790,9 @@ dependencies = [
|
||||
"tauri",
|
||||
"tauri-plugin-deep-link",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
@@ -6873,7 +6817,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-store"
|
||||
version = "2.4.3"
|
||||
version = "2.4.4"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"serde",
|
||||
@@ -6893,7 +6837,7 @@ dependencies = [
|
||||
"iota-crypto",
|
||||
"iota_stronghold",
|
||||
"log",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
"rust-argon2 2.1.0",
|
||||
@@ -6933,7 +6877,7 @@ dependencies = [
|
||||
"time",
|
||||
"tokio",
|
||||
"url",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
"zip 4.0.0",
|
||||
]
|
||||
|
||||
@@ -6962,7 +6906,7 @@ dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"log",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6988,9 +6932,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.11.0"
|
||||
version = "2.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e42bbcb76237351fbaa02f08d808c537dc12eb5a6eabbf3e517b50056334d95"
|
||||
checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
@@ -7013,9 +6957,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.11.0"
|
||||
version = "2.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cadb13dad0c681e1e0a2c49ae488f0e2906ded3d57e7a0017f4aaf46e387117"
|
||||
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
@@ -7039,9 +6983,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.9.0"
|
||||
version = "2.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55f61d2bf7188fbcf2b0ed095b67a6bc498f713c939314bb19eb700118a573b7"
|
||||
checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
@@ -7056,7 +7000,7 @@ dependencies = [
|
||||
"json-patch",
|
||||
"log",
|
||||
"memchr",
|
||||
"phf 0.11.3",
|
||||
"phf",
|
||||
"plist",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -7089,11 +7033,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-winrt-notification"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
|
||||
checksum = "9ed071c670382e85fc2f48ae706492d8c338f4f89bf72520d32f8abfe880aade"
|
||||
dependencies = [
|
||||
"quick-xml 0.37.4",
|
||||
"thiserror 2.0.12",
|
||||
"windows 0.61.1",
|
||||
"windows-version",
|
||||
@@ -7524,9 +7467,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.23.1"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773"
|
||||
checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dirs 6.0.0",
|
||||
@@ -7581,7 +7524,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.9.3",
|
||||
"rand 0.9.4",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
@@ -7774,12 +7717,6 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
@@ -7804,12 +7741,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
@@ -8080,7 +8011,7 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538"
|
||||
dependencies = [
|
||||
"phf 0.13.1",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
"string_cache",
|
||||
"string_cache_codegen",
|
||||
@@ -8180,7 +8111,7 @@ dependencies = [
|
||||
"webview2-com-macros",
|
||||
"webview2-com-sys",
|
||||
"windows 0.61.1",
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
]
|
||||
@@ -8204,7 +8135,7 @@ checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"windows 0.61.1",
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8255,7 +8186,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8298,11 +8229,23 @@ version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
|
||||
dependencies = [
|
||||
"windows-collections",
|
||||
"windows-core",
|
||||
"windows-future",
|
||||
"windows-link",
|
||||
"windows-numerics",
|
||||
"windows-collections 0.2.0",
|
||||
"windows-core 0.61.0",
|
||||
"windows-future 0.2.0",
|
||||
"windows-link 0.1.1",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
||||
dependencies = [
|
||||
"windows-collections 0.3.2",
|
||||
"windows-core 0.62.2",
|
||||
"windows-future 0.3.2",
|
||||
"windows-numerics 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8311,7 +8254,16 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8322,9 +8274,22 @@ checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-link 0.1.1",
|
||||
"windows-result 0.3.2",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.2.1",
|
||||
"windows-result 0.4.1",
|
||||
"windows-strings 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8333,15 +8298,26 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
"windows-core 0.61.0",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-link 0.2.1",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -8350,9 +8326,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
version = "0.59.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -8365,14 +8341,30 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
"windows-core 0.61.0",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8381,9 +8373,20 @@ version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1da3e436dc7653dfdf3da67332e22bff09bb0e28b0239e1624499c7830842e"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-link 0.1.1",
|
||||
"windows-result 0.3.2",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows-result 0.4.1",
|
||||
"windows-strings 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8392,7 +8395,16 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8401,7 +8413,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8449,6 +8470,15 @@ dependencies = [
|
||||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
@@ -8511,13 +8541,22 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-version"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8852,7 +8891,7 @@ dependencies = [
|
||||
"webkit2gtk-sys",
|
||||
"webview2-com",
|
||||
"windows 0.61.1",
|
||||
"windows-core",
|
||||
"windows-core 0.61.0",
|
||||
"windows-version",
|
||||
"x11-dl",
|
||||
]
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ resolver = "2"
|
||||
[workspace.dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
log = "0.4"
|
||||
log = "0.4.21"
|
||||
tauri = { version = "2.10", default-features = false }
|
||||
tauri-build = "2.5"
|
||||
tauri-plugin = "2.5"
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.42]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog-js@2.7.2`
|
||||
- Upgraded to `store-js@2.4.4`
|
||||
|
||||
## \[2.0.41]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `log-js@2.9.0`
|
||||
|
||||
## \[2.0.40]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner-js@2.4.5`
|
||||
- Upgraded to `global-shortcut-js@2.3.2`
|
||||
|
||||
## \[2.0.39]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en" theme="dark">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=0"
|
||||
/>
|
||||
<title>Svelte + Vite App</title>
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<title>API Example App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
+21
-21
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "api",
|
||||
"private": true,
|
||||
"version": "2.0.39",
|
||||
"version": "2.0.42",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false",
|
||||
@@ -11,32 +11,32 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.11.0",
|
||||
"@tauri-apps/plugin-barcode-scanner": "^2.4.4",
|
||||
"@tauri-apps/plugin-biometric": "^2.3.2",
|
||||
"@tauri-apps/plugin-cli": "^2.4.1",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
||||
"@tauri-apps/plugin-dialog": "^2.7.1",
|
||||
"@tauri-apps/plugin-fs": "^2.5.1",
|
||||
"@tauri-apps/plugin-geolocation": "^2.3.2",
|
||||
"@tauri-apps/plugin-global-shortcut": "^2.3.1",
|
||||
"@tauri-apps/plugin-haptics": "^2.3.2",
|
||||
"@tauri-apps/plugin-http": "^2.5.9",
|
||||
"@tauri-apps/plugin-nfc": "^2.3.5",
|
||||
"@tauri-apps/plugin-notification": "^2.3.3",
|
||||
"@tauri-apps/plugin-opener": "^2.5.4",
|
||||
"@tauri-apps/plugin-os": "^2.3.2",
|
||||
"@tauri-apps/plugin-process": "^2.3.1",
|
||||
"@tauri-apps/plugin-shell": "^2.3.5",
|
||||
"@tauri-apps/plugin-store": "^2.4.3",
|
||||
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||
"@tauri-apps/plugin-upload": "^2.4.0",
|
||||
"@tauri-apps/plugin-barcode-scanner": "workspace:*",
|
||||
"@tauri-apps/plugin-biometric": "workspace:*",
|
||||
"@tauri-apps/plugin-cli": "workspace:*",
|
||||
"@tauri-apps/plugin-clipboard-manager": "workspace:*",
|
||||
"@tauri-apps/plugin-dialog": "2",
|
||||
"@tauri-apps/plugin-fs": "workspace:*",
|
||||
"@tauri-apps/plugin-geolocation": "workspace:*",
|
||||
"@tauri-apps/plugin-global-shortcut": "workspace:*",
|
||||
"@tauri-apps/plugin-haptics": "workspace:*",
|
||||
"@tauri-apps/plugin-http": "workspace:*",
|
||||
"@tauri-apps/plugin-nfc": "workspace:*",
|
||||
"@tauri-apps/plugin-notification": "workspace:*",
|
||||
"@tauri-apps/plugin-opener": "workspace:*",
|
||||
"@tauri-apps/plugin-os": "workspace:*",
|
||||
"@tauri-apps/plugin-process": "workspace:*",
|
||||
"@tauri-apps/plugin-shell": "workspace:*",
|
||||
"@tauri-apps/plugin-store": "2",
|
||||
"@tauri-apps/plugin-updater": "workspace:*",
|
||||
"@tauri-apps/plugin-upload": "workspace:*",
|
||||
"@zerodevx/svelte-json-view": "1.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/codicon": "^1.2.49",
|
||||
"@iconify-json/ph": "^1.2.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"@tauri-apps/cli": "2.11.4",
|
||||
"@unocss/extractor-svelte": "^66.6.7",
|
||||
"svelte": "^5.54.0",
|
||||
"unocss": "^66.6.7",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.46]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog@2.7.2`
|
||||
- Upgraded to `store@2.4.4`
|
||||
|
||||
## \[2.0.45]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `log@2.9.0`
|
||||
|
||||
## \[2.0.44]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner@2.4.5`
|
||||
- Upgraded to `global-shortcut@2.3.2`
|
||||
|
||||
## \[2.0.43]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "api"
|
||||
publish = false
|
||||
version = "2.0.43"
|
||||
version = "2.0.46"
|
||||
description = "An example Tauri Application showcasing the api"
|
||||
edition = "2021"
|
||||
rust-version = { workspace = true }
|
||||
@@ -20,12 +20,12 @@ serde = { workspace = true }
|
||||
tiny_http = "0.12"
|
||||
time = "0.3"
|
||||
log = { workspace = true }
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.8.0" }
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.9.0" }
|
||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.5.1", features = [
|
||||
"watch",
|
||||
] }
|
||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.2" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.7.1" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.7.2" }
|
||||
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
||||
"multipart",
|
||||
"cookies",
|
||||
@@ -37,7 +37,7 @@ tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.2" }
|
||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.1" }
|
||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.5.4" }
|
||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.5" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.3" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.4" }
|
||||
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
|
||||
|
||||
[dependencies.tauri]
|
||||
@@ -56,12 +56,12 @@ features = [
|
||||
|
||||
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.1" }
|
||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.1" }
|
||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.2" }
|
||||
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.10.1" }
|
||||
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
|
||||
|
||||
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.4" }
|
||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.5" }
|
||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.5" }
|
||||
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.2" }
|
||||
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.2" }
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
]
|
||||
},
|
||||
"core:default",
|
||||
"core:app:allow-set-app-theme",
|
||||
"fs:default",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-maximize",
|
||||
"core:window:allow-unmaximize",
|
||||
"core:window:allow-toggle-maximize",
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-start-dragging",
|
||||
"notification:default",
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
package com.tauri.api
|
||||
|
||||
class MainActivity : TauriActivity()
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
|
||||
class MainActivity : TauriActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.api" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.api" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.api" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.api" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
+17
-1
@@ -21,7 +21,23 @@ open class BuildTask : DefaultTask() {
|
||||
runTauriCli(executable)
|
||||
} catch (e: Exception) {
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
runTauriCli("$executable.cmd")
|
||||
// Try different Windows-specific extensions
|
||||
val fallbacks = listOf(
|
||||
"$executable.exe",
|
||||
"$executable.cmd",
|
||||
"$executable.bat",
|
||||
)
|
||||
|
||||
var lastException: Exception = e
|
||||
for (fallback in fallbacks) {
|
||||
try {
|
||||
runTauriCli(fallback)
|
||||
return
|
||||
} catch (fallbackException: Exception) {
|
||||
lastException = fallbackException
|
||||
}
|
||||
}
|
||||
throw lastException
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
||||
+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,7 +77,9 @@
|
||||
},
|
||||
"updater": {
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK",
|
||||
"dangerousInsecureTransportProtocol": true,
|
||||
"endpoints": [
|
||||
"http://localhost:5173/updater-test/updater.json",
|
||||
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
|
||||
]
|
||||
}
|
||||
@@ -99,6 +101,9 @@
|
||||
"localePath": "locales/pt-BR.wxl"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nsis": {
|
||||
"compression": "none"
|
||||
}
|
||||
},
|
||||
"iOS": {
|
||||
|
||||
+128
-195
@@ -1,7 +1,16 @@
|
||||
<script>
|
||||
<script module lang="ts">
|
||||
export type ViewProps = {
|
||||
onMessage: (value: unknown) => void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount, tick } from 'svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { MediaQuery } from 'svelte/reactivity'
|
||||
import { getCurrentWindow, type Theme } from '@tauri-apps/api/window'
|
||||
import { getCurrentWebview } from '@tauri-apps/api/webview'
|
||||
import { setTheme } from '@tauri-apps/api/app'
|
||||
import * as os from '@tauri-apps/plugin-os'
|
||||
|
||||
import Welcome from './views/Welcome.svelte'
|
||||
@@ -23,11 +32,10 @@
|
||||
import Biometric from './views/Biometric.svelte'
|
||||
import Geolocation from './views/Geolocation.svelte'
|
||||
import Haptics from './views/Haptics.svelte'
|
||||
|
||||
import { onMount, tick } from 'svelte'
|
||||
import { ask } from '@tauri-apps/plugin-dialog'
|
||||
import Nfc from './views/Nfc.svelte'
|
||||
|
||||
import TitleBar from './lib/TitleBar.svelte'
|
||||
|
||||
const appWindow = getCurrentWindow()
|
||||
|
||||
if (appWindow.label !== 'main') {
|
||||
@@ -148,114 +156,98 @@
|
||||
component: Haptics,
|
||||
icon: 'i-ph-vibrate'
|
||||
}
|
||||
]
|
||||
].filter(Boolean) as {
|
||||
label: string
|
||||
component: typeof Haptics
|
||||
icon: string
|
||||
}[]
|
||||
let selected = $state.raw(views[0])
|
||||
|
||||
let selected = views[0]
|
||||
function select(view) {
|
||||
selected = view
|
||||
}
|
||||
// dark/light themes
|
||||
const preferDark = new MediaQuery('prefers-color-scheme: dark')
|
||||
let theme = $state<Theme | 'auto'>(
|
||||
(localStorage.getItem('theme') as Theme | null) || 'auto'
|
||||
)
|
||||
|
||||
// Window controls
|
||||
let isWindowMaximized
|
||||
onMount(async () => {
|
||||
isWindowMaximized = await appWindow.isMaximized()
|
||||
appWindow.onResized(async () => {
|
||||
isWindowMaximized = await appWindow.isMaximized()
|
||||
})
|
||||
})
|
||||
|
||||
function minimize() {
|
||||
appWindow.minimize()
|
||||
}
|
||||
|
||||
async function toggleMaximize() {
|
||||
;(await appWindow.isMaximized())
|
||||
? appWindow.unmaximize()
|
||||
: appWindow.maximize()
|
||||
}
|
||||
|
||||
let confirmed_close = false
|
||||
async function close() {
|
||||
if (!confirmed_close) {
|
||||
confirmed_close = await ask(
|
||||
'Are you sure that you want to close this window?',
|
||||
{
|
||||
title: 'Tauri API'
|
||||
}
|
||||
)
|
||||
if (confirmed_close) {
|
||||
appWindow.close()
|
||||
}
|
||||
async function switchTheme() {
|
||||
switch (theme) {
|
||||
case 'dark':
|
||||
theme = 'light'
|
||||
break
|
||||
case 'light':
|
||||
theme = 'auto'
|
||||
break
|
||||
case 'auto':
|
||||
theme = 'dark'
|
||||
break
|
||||
}
|
||||
applyTheme()
|
||||
}
|
||||
|
||||
// dark/light
|
||||
let isDark
|
||||
onMount(() => {
|
||||
isDark = localStorage && localStorage.getItem('theme') == 'dark'
|
||||
applyTheme(isDark)
|
||||
function applyTheme() {
|
||||
const isDark = theme === 'auto' ? preferDark.current : theme === 'dark'
|
||||
if (isDark) {
|
||||
document.documentElement.classList.add('dark')
|
||||
document.documentElement.classList.remove('light')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
document.documentElement.classList.add('light')
|
||||
}
|
||||
setTheme(theme === 'auto' ? null : theme)
|
||||
localStorage.setItem('theme', theme)
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
applyTheme()
|
||||
})
|
||||
function applyTheme(isDark) {
|
||||
const html = document.querySelector('html')
|
||||
isDark ? html.classList.add('dark') : html.classList.remove('dark')
|
||||
localStorage && localStorage.setItem('theme', isDark ? 'dark' : '')
|
||||
}
|
||||
function toggleDark() {
|
||||
isDark = !isDark
|
||||
applyTheme(isDark)
|
||||
}
|
||||
|
||||
// Console
|
||||
let messages = writable([])
|
||||
let consoleTextEl
|
||||
async function onMessage(value) {
|
||||
const messages = writable<string[]>([])
|
||||
let consoleTextEl: HTMLDivElement
|
||||
|
||||
// this function is renders HTML without sanitizing it so it's insecure
|
||||
// we only use it with our own input data
|
||||
async function insecureRenderHtml(html: string) {
|
||||
messages.update((r) => [
|
||||
...r,
|
||||
{
|
||||
html:
|
||||
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
|
||||
(typeof value === 'string' ? value : JSON.stringify(value, null, 1)) +
|
||||
'</pre>'
|
||||
}
|
||||
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ${html}</pre>`
|
||||
])
|
||||
await tick()
|
||||
if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight
|
||||
consoleTextEl.scrollTop = consoleTextEl.scrollHeight
|
||||
}
|
||||
|
||||
// this function renders HTML without sanitizing it so it's insecure
|
||||
// we only use it with our own input data
|
||||
async function insecureRenderHtml(html) {
|
||||
messages.update((r) => [
|
||||
...r,
|
||||
{
|
||||
html:
|
||||
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
|
||||
html +
|
||||
'</pre>'
|
||||
}
|
||||
])
|
||||
await tick()
|
||||
if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight
|
||||
async function onMessage(value: unknown) {
|
||||
const valueStr =
|
||||
typeof value === 'string'
|
||||
? value
|
||||
: JSON.stringify(
|
||||
value instanceof ArrayBuffer
|
||||
? Array.from(new Uint8Array(value))
|
||||
: value,
|
||||
null,
|
||||
1
|
||||
)
|
||||
insecureRenderHtml(valueStr)
|
||||
}
|
||||
|
||||
function clear() {
|
||||
messages.update(() => [])
|
||||
}
|
||||
|
||||
let consoleEl, consoleH, cStartY
|
||||
let minConsoleHeight = 50
|
||||
function startResizingConsole(e) {
|
||||
let consoleEl: HTMLDivElement
|
||||
let consoleH = 0
|
||||
let cStartY = 0
|
||||
const minConsoleHeight = 50
|
||||
function startResizingConsole(e: MouseEvent) {
|
||||
cStartY = e.clientY
|
||||
|
||||
const styles = window.getComputedStyle(consoleEl)
|
||||
consoleH = parseInt(styles.height, 10)
|
||||
|
||||
const moveHandler = (e) => {
|
||||
const moveHandler = (e: MouseEvent) => {
|
||||
const dy = e.clientY - cStartY
|
||||
const newH = consoleH - dy
|
||||
consoleEl.style.height = `${
|
||||
newH < minConsoleHeight ? minConsoleHeight : newH
|
||||
}px`
|
||||
consoleEl.style.height = `${newH < minConsoleHeight ? minConsoleHeight : newH}px`
|
||||
}
|
||||
const upHandler = () => {
|
||||
document.removeEventListener('mouseup', upHandler)
|
||||
@@ -265,21 +257,19 @@
|
||||
document.addEventListener('mousemove', moveHandler)
|
||||
}
|
||||
|
||||
let isWindows
|
||||
onMount(async () => {
|
||||
isWindows = (await os.platform()) === 'windows'
|
||||
})
|
||||
let isWindows = os.platform() === 'windows'
|
||||
|
||||
// mobile
|
||||
let isSideBarOpen = false
|
||||
let sidebar
|
||||
let sidebarToggle
|
||||
let isSideBarOpen = $state(false)
|
||||
let sidebar: HTMLElement
|
||||
let sidebarToggle: HTMLElement
|
||||
let isDraggingSideBar = false
|
||||
let draggingStartPosX = 0
|
||||
let draggingEndPosX = 0
|
||||
const clamp = (min, num, max) => Math.min(Math.max(num, min), max)
|
||||
const clamp = (min: number, num: number, max: number) =>
|
||||
Math.min(Math.max(num, min), max)
|
||||
|
||||
function toggleSidebar(sidebar, isSideBarOpen) {
|
||||
function toggleSidebar() {
|
||||
sidebar.style.setProperty(
|
||||
'--translate-x',
|
||||
`${isSideBarOpen ? '0' : '-18.75'}rem`
|
||||
@@ -287,10 +277,9 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
sidebar = document.querySelector('#sidebar')
|
||||
sidebarToggle = document.querySelector('#sidebarToggle')
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!(e.target instanceof Node)) return
|
||||
|
||||
if (sidebarToggle.contains(e.target)) {
|
||||
isSideBarOpen = !isSideBarOpen
|
||||
} else if (isSideBarOpen && !sidebar.contains(e.target)) {
|
||||
@@ -299,6 +288,7 @@
|
||||
})
|
||||
|
||||
document.addEventListener('touchstart', (e) => {
|
||||
if (!(e.target instanceof Node)) return
|
||||
if (sidebarToggle.contains(e.target)) return
|
||||
|
||||
const x = e.touches[0].clientX
|
||||
@@ -330,76 +320,22 @@
|
||||
})
|
||||
})
|
||||
|
||||
$: {
|
||||
const sidebar = document.querySelector('#sidebar')
|
||||
if (sidebar) {
|
||||
toggleSidebar(sidebar, isSideBarOpen)
|
||||
}
|
||||
}
|
||||
$effect(() => {
|
||||
toggleSidebar()
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- custom titlebar for Windows -->
|
||||
{#if isWindows}
|
||||
<div
|
||||
class="w-screen select-none h-8 pl-2 flex justify-between items-center absolute text-primaryText dark:text-darkPrimaryText"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<span class="lt-sm:pl-10 text-darkPrimaryText">Tauri API Validation</span>
|
||||
<span
|
||||
class="
|
||||
h-100%
|
||||
children:h-100% children:w-12 children:inline-flex
|
||||
children:items-center children:justify-center"
|
||||
>
|
||||
<button
|
||||
aria-label="Toggle dark mode"
|
||||
title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'}
|
||||
class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={toggleDark}
|
||||
>
|
||||
{#if isDark}
|
||||
<div class="i-ph-sun"></div>
|
||||
{:else}
|
||||
<div class="i-ph-moon"></div>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
aria-label="Minimize window"
|
||||
title="Minimize"
|
||||
class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={minimize}
|
||||
>
|
||||
<div class="i-codicon-chrome-minimize"></div>
|
||||
</button>
|
||||
<button
|
||||
aria-label="Maximize window"
|
||||
title={isWindowMaximized ? 'Restore' : 'Maximize'}
|
||||
class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
on:click={toggleMaximize}
|
||||
>
|
||||
{#if isWindowMaximized}
|
||||
<div class="i-codicon-chrome-restore"></div>
|
||||
{:else}
|
||||
<div class="i-codicon-chrome-maximize"></div>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
aria-label="Close window"
|
||||
title="Close"
|
||||
class="bg-inherit border-none hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
|
||||
on:click={close}
|
||||
>
|
||||
<div class="i-codicon-chrome-close"></div>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<TitleBar {appWindow} {theme} {switchTheme} />
|
||||
{/if}
|
||||
|
||||
<!-- Sidebar toggle, only visible on small screens -->
|
||||
<div
|
||||
id="sidebarToggle"
|
||||
class="z-2000 sidebar-toggle hidden lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8
|
||||
bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark"
|
||||
bind:this={sidebarToggle}
|
||||
class="z-2000 hidden lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8
|
||||
bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark text-accentText dark:text-darkAccentText"
|
||||
>
|
||||
{#if isSideBarOpen}
|
||||
<span class="i-codicon-close animate-duration-300ms animate-fade-in"></span>
|
||||
@@ -409,10 +345,11 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex h-screen w-screen overflow-hidden children-pt8 children-pb-2 text-primaryText dark:text-darkPrimaryText"
|
||||
class="flex h-screen w-screen overflow-hidden text-primaryText dark:text-darkPrimaryText"
|
||||
>
|
||||
<aside
|
||||
id="sidebar"
|
||||
bind:this={sidebar}
|
||||
class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999
|
||||
bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2"
|
||||
>
|
||||
@@ -420,13 +357,16 @@
|
||||
<img class="p-7" src="tauri_logo.png" alt="Tauri logo" />
|
||||
</a>
|
||||
{#if !isWindows}
|
||||
<a href="##" class="nv justify-between h-8" on:click={toggleDark}>
|
||||
{#if isDark}
|
||||
Switch to Light mode
|
||||
<div class="i-ph-sun"></div>
|
||||
{:else}
|
||||
<a href="##" class="nv justify-between" onclick={switchTheme}>
|
||||
{#if theme === 'auto'}
|
||||
Switch to Dark mode
|
||||
<div class="i-ph-circle-half-fill"></div>
|
||||
{:else if theme === 'dark'}
|
||||
Switch to Light mode
|
||||
<div class="i-ph-moon"></div>
|
||||
{:else if theme === 'light'}
|
||||
Switch to Auto mode
|
||||
<div class="i-ph-sun"></div>
|
||||
{/if}
|
||||
</a>
|
||||
<br />
|
||||
@@ -435,7 +375,7 @@
|
||||
{/if}
|
||||
|
||||
<a
|
||||
class="nv justify-between h-8"
|
||||
class="nv justify-between"
|
||||
target="_blank"
|
||||
href="https://tauri.app/v1/guides/"
|
||||
>
|
||||
@@ -443,7 +383,7 @@
|
||||
<span class="i-codicon-link-external"></span>
|
||||
</a>
|
||||
<a
|
||||
class="nv justify-between h-8"
|
||||
class="nv justify-between"
|
||||
target="_blank"
|
||||
href="https://github.com/tauri-apps/tauri"
|
||||
>
|
||||
@@ -451,7 +391,7 @@
|
||||
<span class="i-codicon-link-external"></span>
|
||||
</a>
|
||||
<a
|
||||
class="nv justify-between h-8"
|
||||
class="nv justify-between"
|
||||
target="_blank"
|
||||
href="https://github.com/tauri-apps/tauri/tree/dev/examples/api"
|
||||
>
|
||||
@@ -461,23 +401,19 @@
|
||||
<br />
|
||||
<div class="bg-white/5 h-2px"></div>
|
||||
<br />
|
||||
<div
|
||||
class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1"
|
||||
>
|
||||
<div class="flex flex-col overflow-y-auto children-flex-none gap-1">
|
||||
{#each views as view}
|
||||
{#if view}
|
||||
<a
|
||||
href="##"
|
||||
class="nv {selected === view ? 'nv_selected' : ''}"
|
||||
on:click={() => {
|
||||
select(view)
|
||||
isSideBarOpen = false
|
||||
}}
|
||||
>
|
||||
<div class="{view.icon} mr-2"></div>
|
||||
<p>{view.label}</p></a
|
||||
>
|
||||
{/if}
|
||||
<a
|
||||
href="##"
|
||||
class="nv {selected === view ? 'nv_selected' : ''}"
|
||||
onclick={() => {
|
||||
selected = view
|
||||
isSideBarOpen = false
|
||||
}}
|
||||
>
|
||||
<div class="{view.icon} mr-2"></div>
|
||||
<p>{view.label}</p></a
|
||||
>
|
||||
{/each}
|
||||
</div>
|
||||
</aside>
|
||||
@@ -489,11 +425,7 @@
|
||||
<h1>{selected.label}</h1>
|
||||
<div class="overflow-y-auto">
|
||||
<div class="mr-2">
|
||||
<svelte:component
|
||||
this={selected.component}
|
||||
{onMessage}
|
||||
{insecureRenderHtml}
|
||||
/>
|
||||
<selected.component {onMessage} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -503,20 +435,21 @@
|
||||
id="console"
|
||||
class="select-none h-15rem grid grid-rows-[2px_2rem_1fr] gap-1 overflow-hidden"
|
||||
>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:mousedown={startResizingConsole}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onmousedown={startResizingConsole}
|
||||
class="bg-black/20 h-2px cursor-ns-resize"
|
||||
></div>
|
||||
<div class="flex justify-between items-center px-2">
|
||||
<p class="font-semibold">Console</p>
|
||||
<button
|
||||
aria-label="Clear Console"
|
||||
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center border-none bg-inherit
|
||||
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center border-none
|
||||
hover:bg-hoverOverlay dark:hover:bg-darkHoverOverlay
|
||||
active:bg-hoverOverlay/25 dark:active:bg-darkHoverOverlay/25
|
||||
"
|
||||
on:click={clear}
|
||||
onclick={clear}
|
||||
>
|
||||
<div class="i-codicon-clear-all"></div>
|
||||
</button>
|
||||
@@ -525,8 +458,8 @@
|
||||
bind:this={consoleTextEl}
|
||||
class="px-2 overflow-y-auto all:font-mono code-block all:text-xs select-text mr-2"
|
||||
>
|
||||
{#each $messages as r}
|
||||
{@html r.html}
|
||||
{#each $messages as messageHtml}
|
||||
{@html messageHtml}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
:root {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
:root.light {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
*:not(h1, h2, h3, h4, h5, h6) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -8,6 +19,11 @@
|
||||
font-family: 'Rubik', sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0.25rem;
|
||||
height: 3px;
|
||||
@@ -33,27 +49,34 @@ code.code-block {
|
||||
width: 18.75rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
@media screen and (width < 640px) {
|
||||
#sidebar {
|
||||
--translate-x: -18.75rem;
|
||||
transform: translateX(var(--translate-x));
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-toggle {
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
#sidebar,
|
||||
main {
|
||||
padding-top: calc(env(safe-area-inset-top) + 2rem);
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
padding: env(safe-area-inset-top) env(safe-area-inset-right)
|
||||
env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||
#sidebar {
|
||||
padding-left: calc(env(safe-area-inset-left) + 0.5rem);
|
||||
}
|
||||
|
||||
main {
|
||||
padding-right: env(safe-area-inset-right);
|
||||
}
|
||||
|
||||
#sidebarToggle {
|
||||
margin-top: calc(env(safe-area-inset-top) + 0.5rem);
|
||||
margin-left: calc(env(safe-area-inset-left) + 0.5rem);
|
||||
}
|
||||
|
||||
#sidebar,
|
||||
#console {
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 24px);
|
||||
padding-bottom: calc(env(safe-area-inset-bottom) + 1.5rem);
|
||||
}
|
||||
|
||||
.transparent {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<script lang="ts">
|
||||
import type { Theme, Window } from '@tauri-apps/api/window'
|
||||
import { ask } from '@tauri-apps/plugin-dialog'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let {
|
||||
appWindow,
|
||||
switchTheme,
|
||||
theme
|
||||
}: { appWindow: Window; switchTheme: () => void; theme: Theme | 'auto' } =
|
||||
$props()
|
||||
|
||||
// Window controls
|
||||
let isWindowMaximized = $state(false)
|
||||
onMount(async () => {
|
||||
isWindowMaximized = await appWindow.isMaximized()
|
||||
appWindow.onResized(async () => {
|
||||
isWindowMaximized = await appWindow.isMaximized()
|
||||
})
|
||||
})
|
||||
|
||||
async function minimize() {
|
||||
await appWindow.minimize()
|
||||
}
|
||||
|
||||
async function toggleMaximize() {
|
||||
await appWindow.toggleMaximize()
|
||||
}
|
||||
|
||||
let confirmedClose = false
|
||||
async function close() {
|
||||
if (!confirmedClose) {
|
||||
confirmedClose = await ask(
|
||||
'Are you sure that you want to close this window?',
|
||||
{
|
||||
title: 'Tauri API'
|
||||
}
|
||||
)
|
||||
if (confirmedClose) {
|
||||
appWindow.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="w-screen select-none h-8 flex justify-between items-center absolute text-primaryText dark:text-darkPrimaryText"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<span
|
||||
class="h-100% pl-2 flex-1 flex items-center lt-sm:pl-10 lt-lg:text-darkPrimaryText [app-region:drag]"
|
||||
>Tauri API Validation</span
|
||||
>
|
||||
<span
|
||||
class="
|
||||
h-100%
|
||||
children:h-100% children:w-12 children:inline-flex
|
||||
children:items-center children:justify-center"
|
||||
>
|
||||
<button
|
||||
aria-label="Toggle dark mode"
|
||||
title={theme ? 'Switch to Light mode' : 'Switch to Dark mode'}
|
||||
class="border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
onclick={switchTheme}
|
||||
>
|
||||
{#if theme === 'auto'}
|
||||
<div title="Switch to Dark mode" class="i-ph-circle-half-fill"></div>
|
||||
{:else if theme === 'dark'}
|
||||
<div title="Switch to Light mode" class="i-ph-moon"></div>
|
||||
{:else if theme === 'light'}
|
||||
<div title="Switch to Auto mode" class="i-ph-sun"></div>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
aria-label="Minimize window"
|
||||
title="Minimize"
|
||||
class="border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
onclick={minimize}
|
||||
>
|
||||
<div class="i-codicon-chrome-minimize"></div>
|
||||
</button>
|
||||
<button
|
||||
aria-label="Maximize window"
|
||||
title={isWindowMaximized ? 'Restore' : 'Maximize'}
|
||||
class="border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
|
||||
onclick={toggleMaximize}
|
||||
>
|
||||
{#if isWindowMaximized}
|
||||
<div class="i-codicon-chrome-restore"></div>
|
||||
{:else}
|
||||
<div class="i-codicon-chrome-maximize"></div>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
aria-label="Close window"
|
||||
title="Close"
|
||||
class="border-none hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
|
||||
onclick={close}
|
||||
>
|
||||
<div class="i-codicon-chrome-close"></div>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -5,7 +5,6 @@
|
||||
import { readFile } from '@tauri-apps/plugin-fs'
|
||||
|
||||
export let onMessage
|
||||
export let insecureRenderHtml
|
||||
let text = 'clipboard message'
|
||||
|
||||
function writeText() {
|
||||
@@ -41,7 +40,7 @@
|
||||
const image = await clipboard.readImage()
|
||||
arrayBufferToBase64(await image.rgba(), function (base64) {
|
||||
const src = 'data:image/png;base64,' + base64
|
||||
insecureRenderHtml('<img src="' + src + '"></img>')
|
||||
onMessage('<img src="' + src + '"></img>')
|
||||
})
|
||||
return
|
||||
} catch (_) {}
|
||||
|
||||
@@ -1,129 +1,138 @@
|
||||
<script>
|
||||
import { open, save, confirm, message } from "@tauri-apps/plugin-dialog";
|
||||
import { readFile } from "@tauri-apps/plugin-fs";
|
||||
<script lang="ts">
|
||||
import {
|
||||
open,
|
||||
save,
|
||||
confirm,
|
||||
message,
|
||||
type PickerMode,
|
||||
type FileAccessMode
|
||||
} from '@tauri-apps/plugin-dialog'
|
||||
import { readFile } from '@tauri-apps/plugin-fs'
|
||||
import type { ViewProps } from '../App.svelte'
|
||||
|
||||
export let onMessage;
|
||||
export let insecureRenderHtml;
|
||||
let defaultPath = null;
|
||||
let filter = null;
|
||||
let multiple = false;
|
||||
let directory = false;
|
||||
let pickerMode = "document";
|
||||
let fileAccessMode = "scoped";
|
||||
let { onMessage }: ViewProps = $props()
|
||||
|
||||
function arrayBufferToBase64(buffer, callback) {
|
||||
let defaultPath: string | undefined = $state()
|
||||
let filter = $state('')
|
||||
let multiple = $state(false)
|
||||
let directory = $state(false)
|
||||
let pickerMode: PickerMode = $state('document')
|
||||
let fileAccessMode: FileAccessMode = $state('scoped')
|
||||
|
||||
function arrayBufferToBase64(
|
||||
buffer: ArrayBuffer,
|
||||
callback: (base64: string) => void
|
||||
) {
|
||||
var blob = new Blob([buffer], {
|
||||
type: "application/octet-binary",
|
||||
});
|
||||
var reader = new FileReader();
|
||||
type: 'application/octet-binary'
|
||||
})
|
||||
var reader = new FileReader()
|
||||
reader.onload = function (evt) {
|
||||
var dataurl = evt.target.result;
|
||||
callback(dataurl.substr(dataurl.indexOf(",") + 1));
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
var dataurl = evt.target!.result as string
|
||||
callback(dataurl.split(',')[1])
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
}
|
||||
|
||||
async function prompt() {
|
||||
confirm("Do you want to do something?")
|
||||
.then((res) => onMessage(res ? "Yes" : "No"))
|
||||
.catch(onMessage);
|
||||
confirm('Do you want to do something?')
|
||||
.then((res) => onMessage(res ? 'Yes' : 'No'))
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
async function promptCustom() {
|
||||
confirm("Is Tauri awesome?", {
|
||||
okLabel: "Absolutely",
|
||||
cancelLabel: "Totally",
|
||||
confirm('Is Tauri awesome?', {
|
||||
okLabel: 'Absolutely',
|
||||
cancelLabel: 'Totally'
|
||||
})
|
||||
.then((res) =>
|
||||
onMessage(
|
||||
res ? "Tauri is absolutely awesome" : "Tauri is totally awesome"
|
||||
res ? 'Tauri is absolutely awesome' : 'Tauri is totally awesome'
|
||||
)
|
||||
)
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
async function msg() {
|
||||
await message("Tauri is awesome!").then((res) => onMessage(res));
|
||||
await message('Tauri is awesome!').then((res) => onMessage(res))
|
||||
}
|
||||
|
||||
async function msgCustom(result) {
|
||||
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
|
||||
async function msgCustom() {
|
||||
const buttons = { yes: 'awesome', no: 'amazing', cancel: 'stunning' }
|
||||
await message(`Tauri is: `, { buttons })
|
||||
.then((res) => onMessage(`Tauri is ${res}`))
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
async function openDialog() {
|
||||
try {
|
||||
var result = await open({
|
||||
title: "My wonderful open dialog",
|
||||
const result = await open({
|
||||
title: 'My wonderful open dialog',
|
||||
defaultPath,
|
||||
filters: filter
|
||||
? [
|
||||
{
|
||||
name: "Tauri Example",
|
||||
extensions: filter.split(",").map((f) => f.trim()),
|
||||
},
|
||||
name: 'Tauri Example',
|
||||
extensions: filter.split(',').map((f) => f.trim())
|
||||
}
|
||||
]
|
||||
: [],
|
||||
multiple,
|
||||
directory,
|
||||
pickerMode,
|
||||
fileAccessMode,
|
||||
fileAccessMode
|
||||
})
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
onMessage(result);
|
||||
onMessage(result)
|
||||
} else if (result === null) {
|
||||
onMessage('user cancelled the selection')
|
||||
} else {
|
||||
var pathToRead = result;
|
||||
var isFile = pathToRead.match(/\S+\.\S+$/g);
|
||||
const pathToRead = result
|
||||
const isFile = pathToRead.match(/\S+\.\S+$/g)
|
||||
|
||||
await readFile(pathToRead)
|
||||
.then(function (res) {
|
||||
if (isFile) {
|
||||
if (
|
||||
pathToRead.includes(".png") ||
|
||||
pathToRead.includes(".jpg") ||
|
||||
pathToRead.includes(".jpeg")
|
||||
) {
|
||||
arrayBufferToBase64(
|
||||
new Uint8Array(res),
|
||||
function (base64) {
|
||||
var src = "data:image/png;base64," + base64;
|
||||
insecureRenderHtml('<img src="' + src + '"></img>');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Convert byte array to UTF-8 string
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const text = decoder.decode(new Uint8Array(res));
|
||||
onMessage(text);
|
||||
}
|
||||
await readFile(pathToRead).then(function (res) {
|
||||
if (isFile) {
|
||||
if (
|
||||
pathToRead.includes('.png')
|
||||
|| pathToRead.includes('.jpg')
|
||||
|| pathToRead.includes('.jpeg')
|
||||
) {
|
||||
arrayBufferToBase64(res.buffer, function (base64) {
|
||||
const src = 'data:image/png;base64,' + base64
|
||||
onMessage('<img src="' + src + '"></img>')
|
||||
})
|
||||
} else {
|
||||
onMessage(res);
|
||||
// Convert byte array to UTF-8 string
|
||||
const decoder = new TextDecoder('utf-8')
|
||||
const text = decoder.decode(res)
|
||||
onMessage(text)
|
||||
}
|
||||
} else {
|
||||
onMessage(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch(exception) {
|
||||
} catch (exception) {
|
||||
onMessage(exception)
|
||||
}
|
||||
}
|
||||
|
||||
function saveDialog() {
|
||||
save({
|
||||
title: "My wonderful save dialog",
|
||||
title: 'My wonderful save dialog',
|
||||
defaultPath,
|
||||
filters: filter
|
||||
? [
|
||||
{
|
||||
name: "Tauri Example",
|
||||
extensions: filter.split(",").map((f) => f.trim()),
|
||||
},
|
||||
name: 'Tauri Example',
|
||||
extensions: filter.split(',').map((f) => f.trim())
|
||||
}
|
||||
]
|
||||
: [],
|
||||
})
|
||||
: []
|
||||
})
|
||||
.then(onMessage)
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -171,15 +180,16 @@
|
||||
<br />
|
||||
|
||||
<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}
|
||||
<button class="btn" id="open-dialog" onclick={openDialog}>Open dialog</button>
|
||||
<button class="btn" id="save-dialog" onclick={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}
|
||||
<button class="btn" id="prompt-dialog" onclick={prompt}>Prompt</button>
|
||||
<button class="btn" id="custom-prompt-dialog" onclick={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>
|
||||
|
||||
<button class="btn" id="message-dialog" onclick={msg}>Message</button>
|
||||
<button class="btn" id="message-dialog" onclick={msgCustom}
|
||||
>Message (custom)</button
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { arrayBufferToBase64 } from '../lib/utils'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
const { onMessage, insecureRenderHtml } = $props()
|
||||
const { onMessage } = $props()
|
||||
|
||||
let path = $state('')
|
||||
let img
|
||||
@@ -118,12 +118,12 @@
|
||||
new Uint8Array(response),
|
||||
function (base64) {
|
||||
const src = 'data:image/png;base64,' + base64
|
||||
insecureRenderHtml('<img src="' + src + '"></img>')
|
||||
onMessage('<img src="' + src + '"></img>')
|
||||
}
|
||||
)
|
||||
} else {
|
||||
const value = String.fromCharCode.apply(null, response)
|
||||
insecureRenderHtml(
|
||||
onMessage(
|
||||
'<textarea id="file-response"></textarea><button id="file-save">Save</button>'
|
||||
)
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
<script>
|
||||
import { check } from '@tauri-apps/plugin-updater'
|
||||
<script lang="ts">
|
||||
import { check, Update } from '@tauri-apps/plugin-updater'
|
||||
import { relaunch } from '@tauri-apps/plugin-process'
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
export let onMessage
|
||||
let { onMessage } = $props()
|
||||
|
||||
let isChecking, isInstalling, newUpdate
|
||||
let totalSize = 0,
|
||||
downloadedSize = 0
|
||||
let isChecking = $state(false)
|
||||
let isInstalling = $state(false)
|
||||
let newUpdate = $state<Update | undefined>()
|
||||
let totalSize = $state(0)
|
||||
let downloadedSize = $state(0)
|
||||
let progress = $derived(
|
||||
totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0
|
||||
)
|
||||
|
||||
async function checkUpdate() {
|
||||
isChecking = true
|
||||
@@ -31,10 +37,10 @@
|
||||
isInstalling = true
|
||||
downloadedSize = 0
|
||||
try {
|
||||
await newUpdate.downloadAndInstall((downloadProgress) => {
|
||||
await newUpdate!.downloadAndInstall((downloadProgress) => {
|
||||
switch (downloadProgress.event) {
|
||||
case 'Started':
|
||||
totalSize = downloadProgress.data.contentLength
|
||||
totalSize = downloadProgress.data.contentLength!
|
||||
break
|
||||
case 'Progress':
|
||||
downloadedSize += downloadProgress.data.chunkLength
|
||||
@@ -54,14 +60,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0
|
||||
onDestroy(() => {
|
||||
newUpdate?.close()
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex children:grow children:h10">
|
||||
{#if !isChecking && !newUpdate}
|
||||
<button class="btn" on:click={checkUpdate}>Check update</button>
|
||||
<button class="btn" onclick={checkUpdate}>Check update</button>
|
||||
{:else if !isInstalling && newUpdate}
|
||||
<button class="btn" on:click={install}>Install update</button>
|
||||
<button class="btn" onclick={install}>Install update</button>
|
||||
{:else}
|
||||
<div class="progress">
|
||||
<span>{progress}%</span>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
*
|
||||
|
||||
!.gitignore
|
||||
!README.md
|
||||
!updater.json
|
||||
@@ -0,0 +1,10 @@
|
||||
To test the updater:
|
||||
|
||||
1. Comment out `verify_signature` inside `plugins/updater/src/updater.rs`
|
||||
2. Run `pnpm tauri build --debug` to build the bundles
|
||||
3. Copy the bundle you want to test to this folder (`examples/api/updater-test/`)
|
||||
4. Run `pnpm tauri dev` and open the Updater tab to check
|
||||
|
||||
If the bundle you're testing doesn't exist in the `updater.json` yet, add it manually and welcome to open an PR
|
||||
|
||||
> The `updater.json` and debug bundles will be served by `vite`
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"notes": "Test update!",
|
||||
"pub_date": "2026-03-01T14:04:20+00:00",
|
||||
"platforms": {
|
||||
"windows-x86_64": {
|
||||
"signature": "",
|
||||
"url": "http://localhost:5173/updater-test/Tauri API_2.0.0_x64_en-US.msi"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export default defineConfig(async () => {
|
||||
port: 5173,
|
||||
strictPort: true,
|
||||
fs: {
|
||||
allow: ['.', '../../tooling/api/dist']
|
||||
allow: ['.']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-15
@@ -15,25 +15,15 @@
|
||||
"@rollup/plugin-node-resolve": "16.0.3",
|
||||
"@rollup/plugin-terser": "1.0.0",
|
||||
"@rollup/plugin-typescript": "12.3.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint": "10.4.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-security": "4.0.0",
|
||||
"prettier": "3.8.1",
|
||||
"rollup": "4.59.0",
|
||||
"eslint-plugin-security": "4.0.1",
|
||||
"prettier": "3.8.3",
|
||||
"rollup": "4.60.3",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "8.58.2"
|
||||
},
|
||||
"minimumReleaseAge": 4320,
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"esbuild@<0.25.0": ">=0.25.0"
|
||||
},
|
||||
"onlyBuiltDependencies": [
|
||||
"esbuild"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": "^10.16.0"
|
||||
}
|
||||
"packageManager": "pnpm@11.13.0"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.5]
|
||||
|
||||
- [`d8645ab3`](https://github.com/tauri-apps/plugins-workspace/commit/d8645ab3e5b508456681eb53275c0837db25aeee) ([#3393](https://github.com/tauri-apps/plugins-workspace/pull/3393) by [@AlexisZankowitch](https://github.com/tauri-apps/plugins-workspace/../../AlexisZankowitch)) Fixed a crash on iOS when `cancel()` is invoked by running the cancel handler on the main thread.
|
||||
|
||||
## \[2.4.4]
|
||||
|
||||
- [`82fbb0c7`](https://github.com/tauri-apps/plugins-workspace/commit/82fbb0c790288eca72af9ade13828ded7700ff90) ([#3221](https://github.com/tauri-apps/plugins-workspace/pull/3221)) On iOS, fixed an application crash happening when the scanner was started when user denied permission before.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-barcode-scanner"
|
||||
version = "2.4.4"
|
||||
version = "2.4.5"
|
||||
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -337,10 +337,11 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
||||
}
|
||||
|
||||
@objc private func cancel(_ invoke: Invoke) {
|
||||
self.invoke?.reject("cancelled")
|
||||
|
||||
destroy()
|
||||
invoke.resolve()
|
||||
DispatchQueue.main.async { [self] in
|
||||
self.invoke?.reject("cancelled")
|
||||
self.destroy()
|
||||
invoke.resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-barcode-scanner",
|
||||
"version": "2.4.4",
|
||||
"version": "2.4.5",
|
||||
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
|
||||
@@ -39,8 +39,8 @@ url = { workspace = true }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
dunce = "1"
|
||||
windows-registry = "0.5"
|
||||
windows-result = "0.3"
|
||||
windows-registry = "0.6"
|
||||
windows-result = "0.4"
|
||||
|
||||
[target."cfg(target_os = \"linux\")".dependencies]
|
||||
rust-ini = "0.21"
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.11.0",
|
||||
"@tauri-apps/plugin-deep-link": "2.4.9"
|
||||
"@tauri-apps/plugin-deep-link": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"@tauri-apps/cli": "2.11.4",
|
||||
"typescript": "^6.0.0",
|
||||
"vite": "^8.0.1"
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.deep_link_example" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.deep_link_example" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.deep_link_example" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<style name="Theme.deep_link_example" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -14,9 +14,11 @@ import { type UnlistenFn, listen } from '@tauri-apps/api/event'
|
||||
* const urls = await getCurrent();
|
||||
* ```
|
||||
*
|
||||
* #### - **Windows / Linux**: This function reads the command line arguments and checks if there's only one value, which must be an URL with scheme matching one of the configured values.
|
||||
* Note that you must manually check the arguments when registering deep link schemes dynamically with [`Self::register`].
|
||||
* Additionally, the deep link might have been provided as a CLI argument so you should check if its format matches what you expect..
|
||||
* #### Platform-specific
|
||||
*
|
||||
* - **Windows / Linux:** This function reads the command line arguments and checks if there's only one value, which must be an URL with scheme matching one of the configured values.
|
||||
* Note that you must manually check the arguments when registering deep link schemes dynamically with [`Self::register`].
|
||||
* Additionally, the deep link might have been provided as a CLI argument so you should check if its format matches what you expect.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@@ -35,7 +37,9 @@ export async function getCurrent(): Promise<string[] | null> {
|
||||
* await register("my-scheme");
|
||||
* ```
|
||||
*
|
||||
* #### - **macOS / Android / iOS**: Unsupported.
|
||||
* #### Platform-specific
|
||||
*
|
||||
* - **macOS / Android / iOS:** Unsupported.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@@ -54,7 +58,9 @@ export async function register(protocol: string): Promise<null> {
|
||||
* await unregister("my-scheme");
|
||||
* ```
|
||||
*
|
||||
* #### - **macOS / Linux / Android / iOS**: Unsupported.
|
||||
* #### Platform-specific
|
||||
*
|
||||
* - **macOS / Linux / Android / iOS:** Unsupported.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@@ -73,7 +79,9 @@ export async function unregister(protocol: string): Promise<null> {
|
||||
* await isRegistered("my-scheme");
|
||||
* ```
|
||||
*
|
||||
* #### - **macOS / Android / iOS**: Unsupported.
|
||||
* #### Platform-specific
|
||||
*
|
||||
* - **macOS / Android / iOS:** Unsupported.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@@ -92,7 +100,9 @@ export async function isRegistered(protocol: string): Promise<boolean> {
|
||||
* await onOpenUrl((urls) => { console.log(urls) });
|
||||
* ```
|
||||
*
|
||||
* #### - **Windows / Linux**: Unsupported without the single-instance plugin. The OS will spawn a new app instance passing the URL as a CLI argument.
|
||||
* #### Platform-specific
|
||||
*
|
||||
* - **Windows / Linux:** Unsupported without the single-instance plugin. The OS will spawn a new app instance passing the URL as a CLI argument.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,6 @@
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0"
|
||||
"@tauri-apps/cli": "2.11.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.7.2]
|
||||
|
||||
- [`40ae0a7f`](https://github.com/tauri-apps/plugins-workspace/commit/40ae0a7fa0ecc9b0cdbd952297f7a17f37308229) ([#3491](https://github.com/tauri-apps/plugins-workspace/pull/3491) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Use `com.google.android.material.dialog.MaterialAlertDialogBuilder` instead of `AlertDialog` so the dialog follows the app's theme
|
||||
|
||||
## \[2.7.1]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.7.1"
|
||||
version = "2.7.2"
|
||||
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
|
||||
@@ -35,8 +35,8 @@ android {
|
||||
dependencies {
|
||||
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.0")
|
||||
implementation("com.google.android.material:material:1.7.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("com.google.android.material:material:1.13.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package app.tauri.dialog
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
@@ -21,6 +20,7 @@ import app.tauri.plugin.Invoke
|
||||
import app.tauri.plugin.JSArray
|
||||
import app.tauri.plugin.JSObject
|
||||
import app.tauri.plugin.Plugin
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
||||
@InvokeArg
|
||||
class Filter {
|
||||
@@ -158,7 +158,7 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
|
||||
Handler(Looper.getMainLooper())
|
||||
.post {
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
val builder = MaterialAlertDialogBuilder(activity)
|
||||
|
||||
if (args.title != null) {
|
||||
builder.setTitle(args.title)
|
||||
@@ -191,8 +191,7 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
}
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
dialog.show()
|
||||
builder.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-dialog",
|
||||
"version": "2.7.1",
|
||||
"version": "2.7.2",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
|
||||
@@ -6,7 +6,7 @@ description = """This denies read access to the
|
||||
`$APPLOCALDATA` folder on linux as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered."""
|
||||
|
||||
[[scope.deny]]
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/**"
|
||||
|
||||
[[permission]]
|
||||
@@ -15,5 +15,5 @@ description = """This denies read access to the
|
||||
`$APPLOCALDATA/EBWebView` folder on windows as the webview data and configuration values are stored here.
|
||||
Allowing access can lead to sensitive information disclosure and should be well considered."""
|
||||
|
||||
[[scope.deny]]
|
||||
[[permission.scope.deny]]
|
||||
path = "$APPLOCALDATA/EBWebView/**"
|
||||
|
||||
+107
-110
@@ -74,7 +74,7 @@ pub type CommandResult<T> = std::result::Result<T, CommandError>;
|
||||
/// Represents either a plain PathBuf or a PathHandle that manages security-scoped resources.
|
||||
pub enum PathKind<R: Runtime> {
|
||||
/// A plain path that doesn't manage security-scoped resources.
|
||||
#[allow(dead_code)] // only used on mobile
|
||||
#[cfg(mobile)] // only used on mobile
|
||||
Path(PathBuf),
|
||||
/// A path handle that manages security-scoped resources and will clean them up on drop.
|
||||
Handle(PathHandle<R>),
|
||||
@@ -84,6 +84,7 @@ impl<R: Runtime> PathKind<R> {
|
||||
/// Get a reference to the underlying path.
|
||||
pub fn as_path(&self) -> &Path {
|
||||
match self {
|
||||
#[cfg(mobile)]
|
||||
PathKind::Path(p) => p.as_ref(),
|
||||
PathKind::Handle(h) => h.as_ref(),
|
||||
}
|
||||
@@ -92,6 +93,7 @@ impl<R: Runtime> PathKind<R> {
|
||||
/// Get a reference to the underlying PathBuf.
|
||||
pub fn as_path_buf(&self) -> &PathBuf {
|
||||
match self {
|
||||
#[cfg(mobile)]
|
||||
PathKind::Path(p) => p,
|
||||
PathKind::Handle(h) => h,
|
||||
}
|
||||
@@ -114,27 +116,13 @@ impl<R: Runtime> AsRef<PathBuf> for PathKind<R> {
|
||||
pub struct FileHandle<R: Runtime> {
|
||||
file: File,
|
||||
path: PathKind<R>,
|
||||
#[allow(dead_code)] // Used in Drop implementation
|
||||
#[cfg(target_os = "ios")]
|
||||
path_: SafeFilePath,
|
||||
#[allow(dead_code)] // Used in Drop implementation
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle: tauri::AppHandle<R>,
|
||||
}
|
||||
|
||||
impl<R: Runtime> FileHandle<R> {
|
||||
fn new(
|
||||
file: File,
|
||||
path: PathKind<R>,
|
||||
path_: SafeFilePath,
|
||||
app_handle: tauri::AppHandle<R>,
|
||||
) -> Self {
|
||||
Self {
|
||||
file,
|
||||
path,
|
||||
path_,
|
||||
app_handle,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the resolved path.
|
||||
pub fn path(&self) -> &Path {
|
||||
self.path.as_path()
|
||||
@@ -155,41 +143,39 @@ impl<R: Runtime> DerefMut for FileHandle<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
impl<R: Runtime> Drop for FileHandle<R> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
// Only clean up if we have a plain PathBuf, not a PathHandle
|
||||
// PathHandle will handle its own cleanup when it's dropped
|
||||
if let PathKind::Path(_) = &self.path {
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
// Only clean up if we have a plain PathBuf, not a PathHandle
|
||||
// PathHandle will handle its own cleanup when it's dropped
|
||||
if let PathKind::Path(_) = &self.path {
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
|
||||
// Only clean up if we're tracking this resource
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
// Only clean up if we're tracking this resource
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!("Stopping accessing security-scoped resource for URL: {url} on drop");
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(
|
||||
url.clone(),
|
||||
));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,38 +222,36 @@ impl<R: Runtime> AsRef<PathBuf> for PathHandle<R> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
impl<R: Runtime> Drop for PathHandle<R> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
use crate::{FilePath, FsExt};
|
||||
// Convert SafeFilePath to FilePath
|
||||
let file_path: FilePath = match &self.path_ {
|
||||
SafeFilePath::Url(url) => FilePath::Url(url.clone()),
|
||||
SafeFilePath::Path(safe_path) => FilePath::Path(safe_path.as_ref().to_owned()),
|
||||
};
|
||||
|
||||
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
// Only clean up if we're tracking this resource (i.e., resolve_path started it)
|
||||
// If start_accessing_security_scoped_resource was used, it won't be in our tracking
|
||||
// and we shouldn't interfere
|
||||
if let FilePath::Url(url) = file_path {
|
||||
if url.scheme() == "file" {
|
||||
let security_scoped_resources =
|
||||
self.app_handle.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
// Only clean up if it's not tracked manually
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
log::debug!(
|
||||
"Stopping accessing security-scoped resource for URL: {url} on drop"
|
||||
);
|
||||
let _ = self
|
||||
.app_handle
|
||||
.fs()
|
||||
.stop_accessing_security_scoped_resource(FilePath::Url(url.clone()));
|
||||
security_scoped_resources.remove(url.as_str());
|
||||
} else {
|
||||
log::debug!("Not cleaning up security-scoped resource for URL: {url} on drop (manually tracked via start_accessing_security_scoped_resource)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,6 +272,7 @@ pub fn create<R: Runtime>(
|
||||
path: SafeFilePath,
|
||||
options: Option<BaseOptions>,
|
||||
) -> CommandResult<ResourceId> {
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
let resolved_path_handle = resolve_path(
|
||||
"create",
|
||||
@@ -303,13 +288,16 @@ pub fn create<R: Runtime>(
|
||||
resolved_path_handle.display()
|
||||
)
|
||||
})?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
let file_handle = FileHandle::new(
|
||||
let file_handle = FileHandle {
|
||||
file,
|
||||
PathKind::Handle(resolved_path_handle),
|
||||
path: PathKind::Handle(resolved_path_handle),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
);
|
||||
};
|
||||
let rid = webview
|
||||
.resources_table()
|
||||
.add(StdFileResource::new(file_handle));
|
||||
@@ -707,7 +695,7 @@ pub async fn read_text_file_lines_next<R: Runtime>(
|
||||
let lines = resource_table.get::<StdLinesResource>(rid)?;
|
||||
|
||||
let ret = StdLinesResource::with_lock(&lines, |lines| -> CommandResult<Vec<u8>> {
|
||||
// This is an optimization to include wether we finished iteration or not (1 or 0)
|
||||
// This is an optimization to include whether we finished iteration or not (1 or 0)
|
||||
// at the end of returned vector so we can use `tauri::ipc::Response`
|
||||
// and avoid serialization overhead of separate values.
|
||||
match lines.next() {
|
||||
@@ -1417,6 +1405,7 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
path: SafeFilePath,
|
||||
open_options: OpenOptions,
|
||||
) -> CommandResult<FileHandle<R>> {
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
let resolved_path_handle = resolve_path(
|
||||
permission,
|
||||
@@ -1436,13 +1425,16 @@ fn resolve_file_in_fs<R: Runtime>(
|
||||
)
|
||||
})?;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
Ok(FileHandle::new(
|
||||
Ok(FileHandle {
|
||||
file,
|
||||
PathKind::Handle(resolved_path_handle),
|
||||
path: PathKind::Handle(resolved_path_handle),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(mobile)]
|
||||
@@ -1456,6 +1448,7 @@ pub fn resolve_file<R: Runtime>(
|
||||
) -> CommandResult<FileHandle<R>> {
|
||||
use crate::FsExt;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
let path_ = path.clone();
|
||||
match path {
|
||||
SafeFilePath::Url(url) => {
|
||||
@@ -1463,13 +1456,16 @@ pub fn resolve_file<R: Runtime>(
|
||||
let file = webview
|
||||
.fs()
|
||||
.open(SafeFilePath::Url(url.clone()), open_options.options)?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let app_handle = webview.app_handle().clone();
|
||||
Ok(FileHandle::new(
|
||||
Ok(FileHandle {
|
||||
file,
|
||||
PathKind::Path(resolved_path),
|
||||
path: PathKind::Path(resolved_path),
|
||||
#[cfg(target_os = "ios")]
|
||||
path_,
|
||||
#[cfg(target_os = "ios")]
|
||||
app_handle,
|
||||
))
|
||||
})
|
||||
}
|
||||
SafeFilePath::Path(path) => resolve_file_in_fs(
|
||||
permission,
|
||||
@@ -1494,36 +1490,37 @@ pub fn resolve_path<R: Runtime>(
|
||||
// On iOS, start accessing security-scoped resource if the path is a file URL
|
||||
// Only if it hasn't been started already via start_accessing_security_scoped_resource
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
if let SafeFilePath::Url(url) = &path {
|
||||
if url.scheme() == "file" {
|
||||
use objc2_foundation::{NSString, NSURL};
|
||||
if let SafeFilePath::Url(url) = &path {
|
||||
if url.scheme() == "file" {
|
||||
use objc2_foundation::{NSString, NSURL};
|
||||
|
||||
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
||||
let security_scoped_resources = webview.state::<crate::SecurityScopedResources>();
|
||||
|
||||
// Check if already active (started via start_accessing_security_scoped_resource)
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
let url_nsstring = NSString::from_str(url.as_str());
|
||||
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
||||
if let Some(ns_url) = ns_url {
|
||||
// Start accessing the security-scoped resource
|
||||
// This is required for files outside the app's sandbox (e.g., from file picker)
|
||||
unsafe {
|
||||
let success = ns_url.startAccessingSecurityScopedResource();
|
||||
if success {
|
||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
||||
// Track it so we know to clean it up
|
||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||
} else {
|
||||
log::warn!("Failed to start accessing security-scoped resource for URL: {}", url.as_str());
|
||||
}
|
||||
// Check if already active (started via start_accessing_security_scoped_resource)
|
||||
if !security_scoped_resources.is_tracked_manually(url.as_str()) {
|
||||
let url_nsstring = NSString::from_str(url.as_str());
|
||||
let ns_url = unsafe { NSURL::URLWithString(&url_nsstring) };
|
||||
if let Some(ns_url) = ns_url {
|
||||
// Start accessing the security-scoped resource
|
||||
// This is required for files outside the app's sandbox (e.g., from file picker)
|
||||
unsafe {
|
||||
let success = ns_url.startAccessingSecurityScopedResource();
|
||||
if success {
|
||||
log::debug!("Started accessing security-scoped resource for URL: {} (via resolve_path)", url.as_str());
|
||||
// Track it so we know to clean it up
|
||||
security_scoped_resources.track_manually(url.as_str().to_string());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Failed to start accessing security-scoped resource for URL: {}",
|
||||
url.as_str()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
||||
}
|
||||
} else {
|
||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
||||
log::debug!("Failed to create NSURL from URL: {}, ignoring security-scoped resource access request", url.as_str());
|
||||
}
|
||||
} else {
|
||||
log::debug!("Security-scoped resource already active for URL: {} (started via start_accessing_security_scoped_resource), skipping", url.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`cb863d57`](https://github.com/tauri-apps/plugins-workspace/commit/cb863d57c60790efc41b2bd77d065bd91b4ef2b1) ([#3408](https://github.com/tauri-apps/plugins-workspace/pull/3408) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update crate `global-hotkey` to 0.8 to fix cpu usage while pressing the keys on windows and to add F13-F24 mappings on Linux/X11.
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-global-shortcut"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
description = "Register global hotkeys listeners on your Tauri application."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -27,4 +27,4 @@ log = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
|
||||
global-hotkey = { version = "0.7", features = ["serde"] }
|
||||
global-hotkey = { version = "0.8", features = ["serde"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-global-shortcut",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.2",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
|
||||
@@ -62,7 +62,7 @@ Afterwards all the plugin's APIs are available through the JavaScript guest bind
|
||||
import { fetch } from '@tauri-apps/plugin-http'
|
||||
const response = await fetch('http://localhost:3003/users/2', {
|
||||
method: 'GET',
|
||||
timeout: 30
|
||||
connectTimeout: 30
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.9.0]
|
||||
|
||||
- [`f08980f1`](https://github.com/tauri-apps/plugins-workspace/commit/f08980f123f191b9505bd290acd8fff0fdefeed9) ([#3445](https://github.com/tauri-apps/plugins-workspace/pull/3445) by [@bajoca05](https://github.com/tauri-apps/plugins-workspace/../../bajoca05)) Added the `FileOpenStrategy` for log rotation. It defaults to append into existing file if any (previous behaviour), and brings a new feature to create a new file per session: `FileOpenStrategy::Rotate`.
|
||||
- [`254f222e`](https://github.com/tauri-apps/plugins-workspace/commit/254f222e0e2bc79370f977855b6b39d956d3b568) ([#3477](https://github.com/tauri-apps/plugins-workspace/pull/3477) by [@bajoca05](https://github.com/tauri-apps/plugins-workspace/../../bajoca05)) Migrated from the `log` crate's `kv_unstable` feature flag to the `kv` feature flag stabilized in `0.4.21`.
|
||||
- [`0c23b8ec`](https://github.com/tauri-apps/plugins-workspace/commit/0c23b8ecfe7c2aca582a81ab7339b11e350b3cac) ([#3446](https://github.com/tauri-apps/plugins-workspace/pull/3446) by [@fee1-dead](https://github.com/tauri-apps/plugins-workspace/../../fee1-dead)) Removed an unused dependency `byte-unit`.
|
||||
|
||||
## \[2.8.0]
|
||||
|
||||
- [`2a625adf`](https://github.com/tauri-apps/plugins-workspace/commit/2a625adff30238904035b86b6e2db7595597e857) ([#3065](https://github.com/tauri-apps/plugins-workspace/pull/3065) by [@BinaryMuse](https://github.com/tauri-apps/plugins-workspace/../../BinaryMuse)) Allow specifying a log formatter per target using the `format` method on `Target`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
description = "Configurable logging for your Tauri app."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -25,8 +25,7 @@ serde_json = { workspace = true }
|
||||
tauri = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
serde_repr = "0.1"
|
||||
byte-unit = "5"
|
||||
log = { workspace = true, features = ["kv_unstable"] }
|
||||
log = { workspace = true, features = ["kv"] }
|
||||
time = { version = "0.3", features = [
|
||||
"formatting",
|
||||
"local-offset",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-log",
|
||||
"version": "2.8.0",
|
||||
"version": "2.9.0",
|
||||
"description": "Configurable logging for your Tauri app.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
|
||||
+152
-4
@@ -43,9 +43,10 @@ mod ios {
|
||||
));
|
||||
}
|
||||
|
||||
const DEFAULT_MAX_FILE_SIZE: u64 = 40000;
|
||||
const DEFAULT_MAX_FILE_SIZE: u64 = 40_000;
|
||||
const DEFAULT_ROTATION_STRATEGY: RotationStrategy = RotationStrategy::KeepOne;
|
||||
const DEFAULT_TIMEZONE_STRATEGY: TimezoneStrategy = TimezoneStrategy::UseUtc;
|
||||
const DEFAULT_FILE_OPEN_STRATEGY: FileOpenStrategy = FileOpenStrategy::Append;
|
||||
const DEFAULT_LOG_TARGETS: [Target; 2] = [
|
||||
Target::new(TargetKind::Stdout),
|
||||
Target::new(TargetKind::LogDir { file_name: None }),
|
||||
@@ -146,15 +147,26 @@ impl TimezoneStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum FileOpenStrategy {
|
||||
/// Open existing file from last session and append, if any.
|
||||
Append,
|
||||
/// Create a new file on each session start, rotating the last session if any.
|
||||
Rotate,
|
||||
}
|
||||
|
||||
/// A custom log writer that rotates the log file when it exceeds specified size.
|
||||
struct RotatingFile {
|
||||
dir: PathBuf,
|
||||
file_name: String,
|
||||
path: PathBuf,
|
||||
/// Maximum file size before rotating in bytes
|
||||
max_size: u64,
|
||||
/// Current file size in bytes
|
||||
current_size: u64,
|
||||
rotation_strategy: RotationStrategy,
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
file_open_strategy: FileOpenStrategy,
|
||||
inner: Option<File>,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
@@ -166,6 +178,7 @@ impl RotatingFile {
|
||||
max_size: u64,
|
||||
rotation_strategy: RotationStrategy,
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
file_open_strategy: FileOpenStrategy,
|
||||
) -> Result<Self, Error> {
|
||||
let dir = dir.as_ref().to_path_buf();
|
||||
let path = dir.join(&file_name).with_extension("log");
|
||||
@@ -178,12 +191,15 @@ impl RotatingFile {
|
||||
current_size: 0,
|
||||
rotation_strategy,
|
||||
timezone_strategy,
|
||||
file_open_strategy,
|
||||
inner: None,
|
||||
buffer: Vec::new(),
|
||||
};
|
||||
|
||||
rotator.open_file()?;
|
||||
if rotator.current_size >= rotator.max_size {
|
||||
if rotator.current_size >= rotator.max_size
|
||||
|| (rotator.current_size > 0 && rotator.file_open_strategy == FileOpenStrategy::Rotate)
|
||||
{
|
||||
rotator.rotate()?;
|
||||
}
|
||||
if let RotationStrategy::KeepSome(keep_count) = rotator.rotation_strategy {
|
||||
@@ -396,6 +412,7 @@ pub struct Builder {
|
||||
dispatch: fern::Dispatch,
|
||||
rotation_strategy: RotationStrategy,
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
file_open_strategy: FileOpenStrategy,
|
||||
max_file_size: u128,
|
||||
targets: Vec<Target>,
|
||||
is_skip_logger: bool,
|
||||
@@ -423,6 +440,7 @@ impl Default for Builder {
|
||||
dispatch,
|
||||
rotation_strategy: DEFAULT_ROTATION_STRATEGY,
|
||||
timezone_strategy: DEFAULT_TIMEZONE_STRATEGY,
|
||||
file_open_strategy: DEFAULT_FILE_OPEN_STRATEGY,
|
||||
max_file_size: DEFAULT_MAX_FILE_SIZE as u128,
|
||||
targets: DEFAULT_LOG_TARGETS.into(),
|
||||
is_skip_logger: false,
|
||||
@@ -435,11 +453,18 @@ impl Builder {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Sets the [`RotationStrategy`].
|
||||
///
|
||||
/// Default is [`RotationStrategy::KeepOne`]
|
||||
pub fn rotation_strategy(mut self, rotation_strategy: RotationStrategy) -> Self {
|
||||
self.rotation_strategy = rotation_strategy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`TimezoneStrategy`].
|
||||
/// Calling this method overrides the format set in [`Self::format`].
|
||||
///
|
||||
/// Default is [`TimezoneStrategy::UseUtc`]
|
||||
pub fn timezone_strategy(mut self, timezone_strategy: TimezoneStrategy) -> Self {
|
||||
self.timezone_strategy = timezone_strategy.clone();
|
||||
|
||||
@@ -456,15 +481,28 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum file size for log rotation.
|
||||
/// Sets the strategy to open the log file.
|
||||
///
|
||||
/// Values larger than `u64::MAX` will be clamped to `u64::MAX`.
|
||||
/// The default is [`FileOpenStrategy::Append`].
|
||||
pub fn file_open_strategy(mut self, file_open_strategy: FileOpenStrategy) -> Self {
|
||||
self.file_open_strategy = file_open_strategy;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum file size in bytes for log rotation.
|
||||
///
|
||||
/// Values larger than [`u64::MAX`] will be clamped to [`u64::MAX`].
|
||||
/// In v3, this parameter will be changed to `u64`.
|
||||
///
|
||||
/// Default is `40_000`
|
||||
pub fn max_file_size(mut self, max_file_size: u128) -> Self {
|
||||
self.max_file_size = max_file_size.min(u64::MAX as u128);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clears the format so that only the message is logged.
|
||||
///
|
||||
/// e.g. `log::info!("message")` will log out `message`
|
||||
pub fn clear_format(mut self) -> Self {
|
||||
self.dispatch = self.dispatch.format(|out, message, _record| {
|
||||
out.finish(format_args!("{message}"));
|
||||
@@ -472,6 +510,37 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the formatter of this dispatch. The closure should accept a
|
||||
/// callback, a message and a log record, and write the resulting
|
||||
/// format to the writer.
|
||||
///
|
||||
/// The log record is passed for completeness, but the `args()` method of
|
||||
/// the record should be ignored, and the [`std::fmt::Arguments`] given
|
||||
/// should be used instead. `record.args()` may be used to retrieve the
|
||||
/// _original_ log message, but in order to allow for true log
|
||||
/// chaining, formatters should use the given message instead whenever
|
||||
/// including the message in the output.
|
||||
///
|
||||
/// To avoid all allocation of intermediate results, the formatter is
|
||||
/// "completed" by calling a callback, which then calls the rest of the
|
||||
/// logging chain with the new formatted message. The callback object keeps
|
||||
/// track of if it was called or not via a stack boolean as well, so if
|
||||
/// you don't use `out.finish` the log message will continue down
|
||||
/// the logger chain unformatted.
|
||||
///
|
||||
/// Example usage:
|
||||
///
|
||||
/// ```
|
||||
/// tauri_plugin_log::Builder::new()
|
||||
/// .format(|out, message, record| {
|
||||
/// out.finish(format_args!(
|
||||
/// "[{} {}] {}",
|
||||
/// record.level(),
|
||||
/// record.target(),
|
||||
/// message
|
||||
/// ))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn format<F>(mut self, formatter: F) -> Self
|
||||
where
|
||||
F: Fn(FormatCallback, &Arguments, &Record) + Sync + Send + 'static,
|
||||
@@ -480,16 +549,64 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the overarching level filter for this logger.
|
||||
/// All messages not already filtered by something set by [`Self::level_for`] will be affected.
|
||||
///
|
||||
/// All messages filtered will be discarded if less severe than the given level.
|
||||
///
|
||||
/// Default level is [`log::LevelFilter::Trace`].
|
||||
pub fn level(mut self, level_filter: impl Into<LevelFilter>) -> Self {
|
||||
self.dispatch = self.dispatch.level(level_filter.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a per-target log level filter. Default target for log messages is
|
||||
/// `crate_name::module_name` or
|
||||
/// `crate_name` for logs in the crate root. Targets can also be set with
|
||||
/// `info!(target: "target-name", ...)`.
|
||||
///
|
||||
/// For each log record fern will first try to match the most specific
|
||||
/// level_for, and then progressively more general ones until either a
|
||||
/// matching level is found, or the default level is used.
|
||||
///
|
||||
/// For example, a log for the target `hyper::http::h1` will first test a
|
||||
/// level_for for `hyper::http::h1`, then for `hyper::http`, then for
|
||||
/// `hyper`, then use the default level.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// A program wants to include a lot of debugging output, but the library
|
||||
/// "hyper" is known to work well, so debug output from it should be
|
||||
/// excluded:
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() {
|
||||
/// tauri_plugin_log::Builder::new()
|
||||
/// .level(log::LevelFilter::Trace)
|
||||
/// .level_for("hyper", log::LevelFilter::Info)
|
||||
/// # ;
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn level_for(mut self, module: impl Into<Cow<'static, str>>, level: LevelFilter) -> Self {
|
||||
self.dispatch = self.dispatch.level_for(module, level);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a custom filter which can reject messages passing through this logger.
|
||||
///
|
||||
/// [`Self::level`] and [`Self::level_for`] are preferred if applicable.
|
||||
///
|
||||
/// Example usage:
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() {
|
||||
/// tauri_plugin_log::Builder::new()
|
||||
/// .level(log::LevelFilter::Info)
|
||||
/// .filter(|metadata| {
|
||||
/// // Reject messages with the `Error` log level.
|
||||
/// metadata.level() != log::LevelFilter::Error
|
||||
/// })
|
||||
/// # }
|
||||
pub fn filter<F>(mut self, filter: F) -> Self
|
||||
where
|
||||
F: Fn(&log::Metadata) -> bool + Send + Sync + 'static,
|
||||
@@ -511,6 +628,19 @@ impl Builder {
|
||||
/// tauri_plugin_log::Builder::new()
|
||||
/// .target(Target::new(TargetKind::Webview));
|
||||
/// ```
|
||||
///
|
||||
/// The default targets are
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tauri_plugin_log::{Target, TargetKind, Builder};
|
||||
/// # Builder::new()
|
||||
/// # .targets(
|
||||
/// [
|
||||
/// Target::new(TargetKind::Stdout),
|
||||
/// Target::new(TargetKind::LogDir { file_name: None }),
|
||||
/// ]
|
||||
/// # );
|
||||
/// ```
|
||||
pub fn target(mut self, target: Target) -> Self {
|
||||
self.targets.push(target);
|
||||
self
|
||||
@@ -543,6 +673,19 @@ impl Builder {
|
||||
/// Target::new(TargetKind::LogDir { file_name: Some("rust".into()) }).filter(|metadata| !metadata.target().starts_with(WEBVIEW_TARGET)),
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// The default targets are
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tauri_plugin_log::{Target, TargetKind, Builder};
|
||||
/// # Builder::new()
|
||||
/// # .targets(
|
||||
/// [
|
||||
/// Target::new(TargetKind::Stdout),
|
||||
/// Target::new(TargetKind::LogDir { file_name: None }),
|
||||
/// ]
|
||||
/// # );
|
||||
/// ```
|
||||
pub fn targets(mut self, targets: impl IntoIterator<Item = Target>) -> Self {
|
||||
self.targets = Vec::from_iter(targets);
|
||||
self
|
||||
@@ -569,6 +712,7 @@ impl Builder {
|
||||
mut dispatch: fern::Dispatch,
|
||||
rotation_strategy: RotationStrategy,
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
file_open_strategy: FileOpenStrategy,
|
||||
max_file_size: u64,
|
||||
targets: Vec<Target>,
|
||||
) -> Result<(log::LevelFilter, Box<dyn log::Log>), Error> {
|
||||
@@ -621,6 +765,7 @@ impl Builder {
|
||||
max_file_size,
|
||||
rotation_strategy.clone(),
|
||||
timezone_strategy.clone(),
|
||||
file_open_strategy.clone(),
|
||||
)?;
|
||||
fern::Output::writer(Box::new(rotator), "\n")
|
||||
}
|
||||
@@ -636,6 +781,7 @@ impl Builder {
|
||||
max_file_size,
|
||||
rotation_strategy.clone(),
|
||||
timezone_strategy.clone(),
|
||||
file_open_strategy.clone(),
|
||||
)?;
|
||||
fern::Output::writer(Box::new(rotator), "\n")
|
||||
}
|
||||
@@ -681,6 +827,7 @@ impl Builder {
|
||||
self.dispatch,
|
||||
self.rotation_strategy,
|
||||
self.timezone_strategy,
|
||||
self.file_open_strategy,
|
||||
self.max_file_size as u64,
|
||||
self.targets,
|
||||
)?;
|
||||
@@ -697,6 +844,7 @@ impl Builder {
|
||||
self.dispatch,
|
||||
self.rotation_strategy,
|
||||
self.timezone_strategy,
|
||||
self.file_open_strategy,
|
||||
self.max_file_size as u64,
|
||||
self.targets,
|
||||
)?;
|
||||
|
||||
@@ -47,6 +47,7 @@ impl<R: Runtime> Nfc<R> {
|
||||
pub fn scan(&self, payload: ScanRequest) -> crate::Result<ScanResponse> {
|
||||
self.0
|
||||
.run_mobile_plugin("scan", payload)
|
||||
.map(|v| ScanResponse { tag: v })
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ glob = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
|
||||
[target."cfg(windows)".dependencies.windows]
|
||||
version = "0.61"
|
||||
version = "0.62"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_UI_Shell_Common",
|
||||
|
||||
@@ -232,10 +232,9 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
let app_dir_ = app_dir.clone();
|
||||
|
||||
if let Some(fs_scope) = &fs_scope {
|
||||
let app_ = app.clone();
|
||||
fs_scope.listen(move |event| {
|
||||
if let tauri::fs::Event::PathAllowed(_) = event {
|
||||
save_scopes(&app_.fs_scope(), &app_dir, &fs_scope_state_path);
|
||||
save_scopes(&app.fs_scope(), &app_dir, &fs_scope_state_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.3]
|
||||
|
||||
- [`4be76900`](https://github.com/tauri-apps/plugins-workspace/commit/4be76900854cae3dc91363dea71b54505896e928) ([#3449](https://github.com/tauri-apps/plugins-workspace/pull/3449) by [@skkap](https://github.com/tauri-apps/plugins-workspace/../../skkap)) Replaced a panic in `calculate_position` with an error return when the window has no associated monitor (e.g. during display sleep or monitor reconfiguration).
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`c0d64bf7`](https://github.com/tauri-apps/plugins-workspace/commit/c0d64bf7d9c0f2c8ed1d2614745e15bbb3cde6a7) ([#3420](https://github.com/tauri-apps/plugins-workspace/pull/3420) by [@UrsDeSwardt](https://github.com/tauri-apps/plugins-workspace/../../UrsDeSwardt)) Removed panics and replaced them with error handling.
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-positioner"
|
||||
version = "2.3.1"
|
||||
version = "2.3.3"
|
||||
description = "Position your windows at well-known locations."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-positioner",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.3",
|
||||
"description": "Position your windows at well-known locations.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
|
||||
@@ -152,7 +152,9 @@ fn calculate_position<R: Runtime>(
|
||||
) -> Result<PhysicalPosition<i32>> {
|
||||
use Position::*;
|
||||
|
||||
let screen = window.current_monitor()?.unwrap();
|
||||
let screen = window.current_monitor()?.ok_or_else(|| {
|
||||
tauri::Error::Io(std::io::Error::other("No monitor found for the window"))
|
||||
})?;
|
||||
// Only use the screen_position for the Tray independent positioning,
|
||||
// because a tray event may not be called on the currently active monitor.
|
||||
let screen_position = screen.position();
|
||||
@@ -225,7 +227,9 @@ fn calculate_position<R: Runtime>(
|
||||
|
||||
PhysicalPosition { x: tray_x, y }
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -236,7 +240,9 @@ fn calculate_position<R: Runtime>(
|
||||
y: tray_y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -257,7 +263,9 @@ fn calculate_position<R: Runtime>(
|
||||
y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -268,7 +276,9 @@ fn calculate_position<R: Runtime>(
|
||||
y: tray_y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -287,7 +297,9 @@ fn calculate_position<R: Runtime>(
|
||||
|
||||
PhysicalPosition { x, y }
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "tray-icon")]
|
||||
@@ -298,7 +310,9 @@ fn calculate_position<R: Runtime>(
|
||||
y: tray_y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
return Err(tauri::Error::Io(std::io::Error::other(
|
||||
"Tray position not set",
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -479,10 +479,8 @@ fn read_line<F: Fn(Vec<u8>) -> CommandEvent + Send + Copy + 'static>(
|
||||
let _ = block_on_task(async move { tx_.send(wrapper(buf)).await });
|
||||
}
|
||||
Err(e) => {
|
||||
let tx_ = tx.clone();
|
||||
let _ = block_on_task(
|
||||
async move { tx_.send(CommandEvent::Error(e.to_string())).await },
|
||||
);
|
||||
let _ =
|
||||
block_on_task(async move { tx.send(CommandEvent::Error(e.to_string())).await });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.3]
|
||||
|
||||
- [`d1573877`](https://github.com/tauri-apps/plugins-workspace/commit/d1573877226e609461761aa538cd0ca4f24d22be) ([#3466](https://github.com/tauri-apps/plugins-workspace/pull/3466) by [@bajoca05](https://github.com/tauri-apps/plugins-workspace/../../bajoca05)) Fix blocked thread on the single-instance plugin for MacOS: replace standard `UnixListener` with `tokio::net::UnixListener`, so the task can yield.
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-single-instance"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
description = "Ensure a single instance of your tauri app is running."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -24,9 +24,10 @@ tracing = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tauri-plugin-deep-link = { path = "../deep-link", version = "2.4.9", optional = true }
|
||||
semver = { version = "1", optional = true }
|
||||
tokio = { version = "1", features = ["net"] }
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies.windows-sys]
|
||||
version = "0.60"
|
||||
version = "0.61"
|
||||
features = [
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_DataExchange",
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0"
|
||||
"@tauri-apps/cli": "2.11.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{
|
||||
io::{BufWriter, Error, ErrorKind, Read, Write},
|
||||
os::unix::net::{UnixListener, UnixStream},
|
||||
io::{BufWriter, Error, ErrorKind, Write},
|
||||
os::unix::net::UnixStream,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ use tauri::{
|
||||
plugin::{self, TauriPlugin},
|
||||
AppHandle, Config, Manager, RunEvent, Runtime,
|
||||
};
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
pub fn init<R: Runtime>(cb: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
||||
plugin::Builder::new("single-instance")
|
||||
@@ -31,7 +32,7 @@ pub fn init<R: Runtime>(cb: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
||||
ErrorKind::NotFound | ErrorKind::ConnectionRefused => {
|
||||
// This process claims itself as singleton as likely none exists
|
||||
socket_cleanup(&socket);
|
||||
listen_for_other_instances(&socket, app.clone(), cb);
|
||||
listen_for_other_instances(socket, app.clone(), cb);
|
||||
}
|
||||
_ => {
|
||||
tracing::debug!(
|
||||
@@ -92,42 +93,40 @@ fn notify_singleton(socket: &PathBuf) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
fn listen_for_other_instances<A: Runtime>(
|
||||
socket: &PathBuf,
|
||||
socket: PathBuf,
|
||||
app: AppHandle<A>,
|
||||
mut cb: Box<SingleInstanceCallback<A>>,
|
||||
) {
|
||||
match UnixListener::bind(socket) {
|
||||
Ok(listener) => {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(mut stream) => {
|
||||
let mut s = String::new();
|
||||
match stream.read_to_string(&mut s) {
|
||||
Ok(_) => {
|
||||
let (cwd, args) = s.split_once("\0\0").unwrap_or_default();
|
||||
let args: Vec<String> =
|
||||
args.split('\0').map(String::from).collect();
|
||||
cb(app.app_handle(), args, cwd.to_string());
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::debug!("single_instance failed to be notified: {e}")
|
||||
}
|
||||
tauri::async_runtime::spawn(async move {
|
||||
match tokio::net::UnixListener::bind(socket) {
|
||||
Ok(listener) => loop {
|
||||
match listener.accept().await {
|
||||
Ok((mut stream, _addr)) => {
|
||||
let mut s = String::new();
|
||||
match stream.read_to_string(&mut s).await {
|
||||
Ok(_) => {
|
||||
let (cwd, args) = s.split_once("\0\0").unwrap_or_default();
|
||||
let args: Vec<String> =
|
||||
args.split('\0').map(String::from).collect();
|
||||
cb(app.app_handle(), args, cwd.to_string());
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::debug!("single_instance failed to be notified: {e}")
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::debug!("single_instance failed to be notified: {}", err);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::debug!("single_instance failed to be notified: {}", err);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
Err(err) => {
|
||||
tracing::error!(
|
||||
"single_instance failed to listen to other processes - launching normally: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!(
|
||||
"single_instance failed to listen to other processes - launching normally: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.4]
|
||||
|
||||
- [`2ed6d6c1`](https://github.com/tauri-apps/plugins-workspace/commit/2ed6d6c1de4f5051b87cb6a2c5ac45320c444989) ([#3499](https://github.com/tauri-apps/plugins-workspace/pull/3499) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `StoreOptions` requires `defaults` field
|
||||
|
||||
## \[2.4.3]
|
||||
|
||||
- [`964e13f1`](https://github.com/tauri-apps/plugins-workspace/commit/964e13f124ad1feeb93c10168b265dc4936f738c) ([#3395](https://github.com/tauri-apps/plugins-workspace/pull/3395) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix a deadlock when calling `Store::set` while exiting (on `RunEvent::Exit`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-store"
|
||||
version = "2.4.3"
|
||||
version = "2.4.4"
|
||||
description = "Simple, persistent key-value store."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"@tauri-apps/cli": "2.11.4",
|
||||
"typescript": "^6.0.0",
|
||||
"vite": "^8.0.1"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export type StoreOptions = {
|
||||
/**
|
||||
* Default value of the store
|
||||
*/
|
||||
defaults: { [key: string]: unknown }
|
||||
defaults?: { [key: string]: unknown }
|
||||
/**
|
||||
* Auto save on modification with debounce duration in milliseconds, it's 100ms by default, pass in `false` to disable it
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-store",
|
||||
"version": "2.4.3",
|
||||
"version": "2.4.4",
|
||||
"description": "Simple, persistent key-value store.",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
|
||||
@@ -50,7 +50,7 @@ percent-encoding = "2.3"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies]
|
||||
zip = { version = "4", default-features = false, optional = true }
|
||||
windows-sys = { version = "0.60.0", features = [
|
||||
windows-sys = { version = "0.61.0", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_UI_Shell",
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(t){"use strict";function e(t,e,s,n){if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?n:"a"===s?n.call(t):n?n.value:e.get(t)}function s(t,e,s,n,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,s),s}var n,i,a,r,o;"function"==typeof SuppressedError&&SuppressedError;const d="__TAURI_TO_IPC_KEY__";class c{constructor(t){n.set(this,void 0),i.set(this,0),a.set(this,[]),r.set(this,void 0),s(this,n,t||(()=>{})),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}(t=>{const o=t.index;if("end"in t)return void(o==e(this,i,"f")?this.cleanupCallback():s(this,r,o));const d=t.message;if(o==e(this,i,"f")){for(e(this,n,"f").call(this,d),s(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,a,"f");){const t=e(this,a,"f")[e(this,i,"f")];e(this,n,"f").call(this,t),delete e(this,a,"f")[e(this,i,"f")],s(this,i,e(this,i,"f")+1)}e(this,i,"f")===e(this,r,"f")&&this.cleanupCallback()}else e(this,a,"f")[o]=d})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(t){s(this,n,t)}get onmessage(){return e(this,n,"f")}[(n=new WeakMap,i=new WeakMap,a=new WeakMap,r=new WeakMap,d)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[d]()}}async function l(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}class h{get rid(){return e(this,o,"f")}constructor(t){o.set(this,void 0),s(this,o,t)}async close(){return l("plugin:resources|close",{rid:this.rid})}}o=new WeakMap;class u extends h{constructor(t){super(t.rid),this.available=!0,this.currentVersion=t.currentVersion,this.version=t.version,this.date=t.date,this.body=t.body,this.rawJson=t.rawJson}async download(t,e){_(e);const s=new c;t&&(s.onmessage=t);const n=await l("plugin:updater|download",{onEvent:s,rid:this.rid,...e});this.downloadedBytes=new h(n)}async install(){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await l("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid}),this.downloadedBytes=void 0}async downloadAndInstall(t,e){_(e);const s=new c;t&&(s.onmessage=t),await l("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...e})}async close(){await(this.downloadedBytes?.close()),await super.close()}}function _(t){t?.headers&&(t.headers=Array.from(new Headers(t.headers).entries()))}return t.Update=u,t.check=async function(t){_(t);const e=await l("plugin:updater|check",{...t});return e?new u(e):null},t}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(t){"use strict";function e(t,e,s,n){if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?n:"a"===s?n.call(t):n?n.value:e.get(t)}function s(t,e,s,n,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,s),s}var n,i,a,r,o;"function"==typeof SuppressedError&&SuppressedError;const d="__TAURI_TO_IPC_KEY__";class c{constructor(t){n.set(this,void 0),i.set(this,0),a.set(this,[]),r.set(this,void 0),s(this,n,t||(()=>{})),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}(t=>{const o=t.index;if("end"in t)return void(o==e(this,i,"f")?this.cleanupCallback():s(this,r,o));const d=t.message;if(o==e(this,i,"f")){for(e(this,n,"f").call(this,d),s(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,a,"f");){const t=e(this,a,"f")[e(this,i,"f")];e(this,n,"f").call(this,t),delete e(this,a,"f")[e(this,i,"f")],s(this,i,e(this,i,"f")+1)}e(this,i,"f")===e(this,r,"f")&&this.cleanupCallback()}else e(this,a,"f")[o]=d})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(t){s(this,n,t)}get onmessage(){return e(this,n,"f")}[(n=new WeakMap,i=new WeakMap,a=new WeakMap,r=new WeakMap,d)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[d]()}}async function l(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}class h{get rid(){return e(this,o,"f")}constructor(t){o.set(this,void 0),s(this,o,t)}async close(){return l("plugin:resources|close",{rid:this.rid})}}o=new WeakMap;class u extends h{constructor(t){super(t.rid),this.available=!0,this.currentVersion=t.currentVersion,this.version=t.version,this.date=t.date,this.body=t.body,this.rawJson=t.rawJson}async download(t,e){_(e);const s=new c;t&&(s.onmessage=t);const n=await l("plugin:updater|download",{onEvent:s,rid:this.rid,...e});this.downloadedBytes=new h(n)}async install(t){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await l("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid,...t}),this.downloadedBytes=void 0}async downloadAndInstall(t,e){_(e);const s=new c;t&&(s.onmessage=t),await l("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...e})}async close(){await(this.downloadedBytes?.close()),await super.close()}}function _(t){t?.headers&&(t.headers=Array.from(new Headers(t.headers).entries()))}return t.Update=u,t.check=async function(t){_(t);const e=await l("plugin:updater|check",{...t});return e?new u(e):null},t}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}
|
||||
|
||||
@@ -40,6 +40,14 @@ interface DownloadOptions {
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
/** Options used when installing an update */
|
||||
interface InstallOptions {
|
||||
/**
|
||||
* If the Windows installer should restart the app after installed, default is `true`
|
||||
*/
|
||||
restartAfterInstall?: boolean
|
||||
}
|
||||
|
||||
interface UpdateMetadata {
|
||||
rid: number
|
||||
currentVersion: string
|
||||
@@ -95,14 +103,15 @@ class Update extends Resource {
|
||||
}
|
||||
|
||||
/** Install downloaded updater package */
|
||||
async install(): Promise<void> {
|
||||
async install(options?: InstallOptions): Promise<void> {
|
||||
if (!this.downloadedBytes) {
|
||||
throw new Error('Update.install called before Update.download')
|
||||
}
|
||||
|
||||
await invoke('plugin:updater|install', {
|
||||
updateRid: this.rid,
|
||||
bytesRid: this.downloadedBytes.rid
|
||||
bytesRid: this.downloadedBytes.rid,
|
||||
...options
|
||||
})
|
||||
|
||||
// Don't need to call close, we did it in rust side already
|
||||
@@ -112,7 +121,7 @@ class Update extends Resource {
|
||||
/** Downloads the updater package and installs it */
|
||||
async downloadAndInstall(
|
||||
onEvent?: (progress: DownloadEvent) => void,
|
||||
options?: DownloadOptions
|
||||
options?: DownloadOptions & InstallOptions
|
||||
): Promise<void> {
|
||||
convertToRustHeaders(options)
|
||||
const channel = new Channel<DownloadEvent>()
|
||||
|
||||
@@ -142,12 +142,22 @@ pub(crate) async fn install<R: Runtime>(
|
||||
webview: Webview<R>,
|
||||
update_rid: ResourceId,
|
||||
bytes_rid: ResourceId,
|
||||
restart_after_install: Option<bool>,
|
||||
) -> Result<()> {
|
||||
let update = webview.resources_table().get::<Update>(update_rid)?;
|
||||
let bytes = webview
|
||||
.resources_table()
|
||||
.get::<DownloadedBytes>(bytes_rid)?;
|
||||
update.install(&bytes.0)?;
|
||||
|
||||
if let Some(restart_after_install) = restart_after_install {
|
||||
let update = (*update).clone();
|
||||
update
|
||||
.restart_after_install(restart_after_install)
|
||||
.install(&bytes.0)?;
|
||||
} else {
|
||||
update.install(&bytes.0)?;
|
||||
}
|
||||
|
||||
let _ = webview.resources_table().close(bytes_rid);
|
||||
Ok(())
|
||||
}
|
||||
@@ -159,6 +169,7 @@ pub(crate) async fn download_and_install<R: Runtime>(
|
||||
on_event: Channel<DownloadEvent>,
|
||||
headers: Option<Vec<(String, String)>>,
|
||||
timeout: Option<u64>,
|
||||
restart_after_install: Option<bool>,
|
||||
) -> Result<()> {
|
||||
let update = webview.resources_table().get::<Update>(rid)?;
|
||||
|
||||
@@ -176,6 +187,10 @@ pub(crate) async fn download_and_install<R: Runtime>(
|
||||
update.timeout = Some(Duration::from_millis(timeout));
|
||||
}
|
||||
|
||||
if let Some(restart_after_install) = restart_after_install {
|
||||
update = update.restart_after_install(restart_after_install);
|
||||
}
|
||||
|
||||
let mut first_chunk = true;
|
||||
|
||||
update
|
||||
|
||||
@@ -32,17 +32,30 @@ impl WindowsUpdateInstallMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn msi_restart_after_install_args(&self) -> &'static [&'static str] {
|
||||
&["AUTOLAUNCHAPP=True"]
|
||||
}
|
||||
|
||||
/// Returns the associated nsis arguments.
|
||||
pub fn nsis_args(&self) -> &'static [&'static str] {
|
||||
// `/P`: Passive
|
||||
// `/S`: Silent
|
||||
// `/R`: Restart
|
||||
match self {
|
||||
Self::Passive => &["/P", "/R"],
|
||||
Self::Quiet => &["/S", "/R"],
|
||||
Self::Passive => &["/P"],
|
||||
Self::Quiet => &["/S"],
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn nsis_restart_after_install_args(&self) -> &'static [&'static str] {
|
||||
match self {
|
||||
Self::BasicUi => &[],
|
||||
_ => &["/R"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for WindowsUpdateInstallMode {
|
||||
@@ -63,6 +76,8 @@ impl Display for WindowsUpdateInstallMode {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WindowsConfig {
|
||||
/// Additional arguments given to the NSIS or WiX installer.
|
||||
///
|
||||
/// Note: this applies to both WiX and NSIS installers
|
||||
#[serde(
|
||||
default,
|
||||
alias = "installer-args",
|
||||
|
||||
@@ -83,9 +83,9 @@ impl<R: Runtime, T: Manager<R>> UpdaterExt<R> for T {
|
||||
builder = builder.target(target);
|
||||
}
|
||||
|
||||
let args = self.env().args_os;
|
||||
if !args.is_empty() {
|
||||
builder = builder.current_exe_args(args);
|
||||
#[cfg(windows)]
|
||||
{
|
||||
builder = builder.current_exe_args(self.env().args_os);
|
||||
}
|
||||
|
||||
builder.version_comparator = version_comparator.clone();
|
||||
|
||||
+212
-148
@@ -129,16 +129,34 @@ impl RemoteRelease {
|
||||
pub type OnBeforeExit = Arc<dyn Fn() + Send + Sync + 'static>;
|
||||
pub type OnBeforeRequest = Arc<dyn Fn(ClientBuilder) -> ClientBuilder + Send + Sync + 'static>;
|
||||
pub type VersionComparator = Arc<dyn Fn(Version, RemoteRelease) -> bool + Send + Sync>;
|
||||
#[cfg(target_os = "macos")]
|
||||
type MainThreadClosure = Box<dyn FnOnce() + Send + Sync + 'static>;
|
||||
type RunOnMainThread =
|
||||
Box<dyn Fn(MainThreadClosure) -> std::result::Result<(), tauri::Error> + Send + Sync + 'static>;
|
||||
#[cfg(target_os = "macos")]
|
||||
type RunOnMainThread = Arc<dyn Fn(MainThreadClosure) -> tauri::Result<()> + Send + Sync + 'static>;
|
||||
|
||||
// TODO: Move more fields to this in v3 if we can mark those fields non `pub`
|
||||
/// Updater context shared between [`UpdaterBuilder`], [`Updater`] and [`Update`]
|
||||
#[derive(Clone)]
|
||||
struct UpdaterContext {
|
||||
config: Config,
|
||||
configure_client: Option<OnBeforeRequest>,
|
||||
#[cfg(target_os = "macos")]
|
||||
run_on_main_thread: RunOnMainThread,
|
||||
/// App name, used for creating named tempfiles
|
||||
#[cfg(windows)]
|
||||
app_name: String,
|
||||
#[cfg(windows)]
|
||||
installer_args: Vec<OsString>,
|
||||
#[cfg(windows)]
|
||||
current_exe_args: Vec<OsString>,
|
||||
#[cfg(windows)]
|
||||
on_before_exit: Option<OnBeforeExit>,
|
||||
#[cfg(windows)]
|
||||
restart_after_install: bool,
|
||||
}
|
||||
|
||||
pub struct UpdaterBuilder {
|
||||
#[allow(dead_code)]
|
||||
run_on_main_thread: RunOnMainThread,
|
||||
app_name: String,
|
||||
current_version: Version,
|
||||
config: Config,
|
||||
pub(crate) version_comparator: Option<VersionComparator>,
|
||||
executable_path: Option<PathBuf>,
|
||||
target: Option<String>,
|
||||
@@ -147,27 +165,38 @@ pub struct UpdaterBuilder {
|
||||
timeout: Option<Duration>,
|
||||
proxy: Option<Url>,
|
||||
no_proxy: bool,
|
||||
installer_args: Vec<OsString>,
|
||||
current_exe_args: Vec<OsString>,
|
||||
on_before_exit: Option<OnBeforeExit>,
|
||||
configure_client: Option<OnBeforeRequest>,
|
||||
context: UpdaterContext,
|
||||
}
|
||||
|
||||
impl UpdaterBuilder {
|
||||
pub(crate) fn new<R: Runtime>(app: &AppHandle<R>, config: crate::Config) -> Self {
|
||||
let app_ = app.clone();
|
||||
let run_on_main_thread = move |f| app_.run_on_main_thread(f);
|
||||
#[cfg(target_os = "macos")]
|
||||
let run_on_main_thread = {
|
||||
let app_ = app.clone();
|
||||
Arc::new(move |f| app_.run_on_main_thread(f))
|
||||
};
|
||||
Self {
|
||||
run_on_main_thread: Box::new(run_on_main_thread),
|
||||
installer_args: config
|
||||
.windows
|
||||
.as_ref()
|
||||
.map(|w| w.installer_args.clone())
|
||||
.unwrap_or_default(),
|
||||
current_exe_args: Vec::new(),
|
||||
app_name: app.package_info().name.clone(),
|
||||
context: UpdaterContext {
|
||||
#[cfg(windows)]
|
||||
installer_args: config
|
||||
.windows
|
||||
.as_ref()
|
||||
.map(|w| w.installer_args.clone())
|
||||
.unwrap_or_default(),
|
||||
config,
|
||||
configure_client: None,
|
||||
#[cfg(target_os = "macos")]
|
||||
run_on_main_thread,
|
||||
#[cfg(windows)]
|
||||
app_name: app.package_info().name.clone(),
|
||||
#[cfg(windows)]
|
||||
current_exe_args: Vec::new(),
|
||||
#[cfg(windows)]
|
||||
on_before_exit: None,
|
||||
#[cfg(windows)]
|
||||
restart_after_install: true,
|
||||
},
|
||||
current_version: app.package_info().version.clone(),
|
||||
config,
|
||||
version_comparator: None,
|
||||
executable_path: None,
|
||||
target: None,
|
||||
@@ -176,8 +205,6 @@ impl UpdaterBuilder {
|
||||
timeout: None,
|
||||
proxy: None,
|
||||
no_proxy: false,
|
||||
on_before_exit: None,
|
||||
configure_client: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +224,7 @@ impl UpdaterBuilder {
|
||||
pub fn endpoints(mut self, endpoints: Vec<Url>) -> Result<Self> {
|
||||
crate::config::validate_endpoints(
|
||||
&endpoints,
|
||||
self.config.dangerous_insecure_transport_protocol,
|
||||
self.context.config.dangerous_insecure_transport_protocol,
|
||||
)?;
|
||||
|
||||
self.endpoints.replace(endpoints);
|
||||
@@ -251,26 +278,40 @@ impl UpdaterBuilder {
|
||||
}
|
||||
|
||||
pub fn pubkey<S: Into<String>>(mut self, pubkey: S) -> Self {
|
||||
self.config.pubkey = pubkey.into();
|
||||
self.context.config.pubkey = pubkey.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an argument to pass to the Windows installer.
|
||||
///
|
||||
/// Note: this applies to both WiX and NSIS installers
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn installer_arg<S>(mut self, arg: S) -> Self
|
||||
where
|
||||
S: Into<OsString>,
|
||||
{
|
||||
self.installer_args.push(arg.into());
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context.installer_args.push(arg.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds multiple arguments to pass to the Windows installer.
|
||||
///
|
||||
/// Note: this applies to both WiX and NSIS installers
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn installer_args<I, S>(mut self, args: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: Into<OsString>,
|
||||
{
|
||||
self.installer_args.extend(args.into_iter().map(Into::into));
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context
|
||||
.installer_args
|
||||
.extend(args.into_iter().map(Into::into));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@@ -280,14 +321,32 @@ impl UpdaterBuilder {
|
||||
/// [`Self::installer_arg`], [`crate::Builder::installer_arg`]
|
||||
/// and the `plugins > updater > windows > installerArgs` config,
|
||||
/// not the ones managed by us (e.g. `/UPDATER` flag passed to the NSIS installer)
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn clear_installer_args(mut self) -> Self {
|
||||
self.installer_args.clear();
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context.installer_args.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Function to run before we run the installer and exit the app through `std::process::exit(0)` on Windows
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn on_before_exit<F: Fn() + Send + Sync + 'static>(mut self, f: F) -> Self {
|
||||
self.on_before_exit.replace(Arc::new(f));
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context.on_before_exit.replace(Arc::new(f));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// If the Windows installer should restart the app after installed, default is `true`
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn restart_after_install(mut self, restart_after_install: bool) -> Self {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context.restart_after_install = restart_after_install;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@@ -299,14 +358,14 @@ impl UpdaterBuilder {
|
||||
mut self,
|
||||
f: F,
|
||||
) -> Self {
|
||||
self.configure_client.replace(Arc::new(f));
|
||||
self.context.configure_client.replace(Arc::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Updater> {
|
||||
let endpoints = self
|
||||
.endpoints
|
||||
.unwrap_or_else(|| self.config.endpoints.clone());
|
||||
.unwrap_or_else(|| self.context.config.endpoints.clone());
|
||||
|
||||
if endpoints.is_empty() {
|
||||
return Err(Error::EmptyEndpoints);
|
||||
@@ -324,44 +383,36 @@ impl UpdaterBuilder {
|
||||
};
|
||||
|
||||
Ok(Updater {
|
||||
run_on_main_thread: Arc::new(self.run_on_main_thread),
|
||||
config: self.config,
|
||||
app_name: self.app_name,
|
||||
current_version: self.current_version,
|
||||
version_comparator: self.version_comparator,
|
||||
timeout: self.timeout,
|
||||
proxy: self.proxy,
|
||||
no_proxy: self.no_proxy,
|
||||
endpoints,
|
||||
installer_args: self.installer_args,
|
||||
current_exe_args: self.current_exe_args,
|
||||
arch,
|
||||
target: self.target,
|
||||
headers: self.headers,
|
||||
extract_path,
|
||||
on_before_exit: self.on_before_exit,
|
||||
configure_client: self.configure_client,
|
||||
context: self.context.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl UpdaterBuilder {
|
||||
pub(crate) fn current_exe_args<I, S>(mut self, args: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: Into<OsString>,
|
||||
{
|
||||
self.current_exe_args
|
||||
self.context
|
||||
.current_exe_args
|
||||
.extend(args.into_iter().map(Into::into));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Updater {
|
||||
#[allow(dead_code)]
|
||||
run_on_main_thread: Arc<RunOnMainThread>,
|
||||
config: Config,
|
||||
app_name: String,
|
||||
current_version: Version,
|
||||
version_comparator: Option<VersionComparator>,
|
||||
timeout: Option<Duration>,
|
||||
@@ -374,12 +425,7 @@ pub struct Updater {
|
||||
target: Option<String>,
|
||||
headers: HeaderMap,
|
||||
extract_path: PathBuf,
|
||||
on_before_exit: Option<OnBeforeExit>,
|
||||
configure_client: Option<OnBeforeRequest>,
|
||||
#[allow(unused)]
|
||||
installer_args: Vec<OsString>,
|
||||
#[allow(unused)]
|
||||
current_exe_args: Vec<OsString>,
|
||||
context: UpdaterContext,
|
||||
}
|
||||
|
||||
impl Updater {
|
||||
@@ -449,10 +495,10 @@ impl Updater {
|
||||
}
|
||||
|
||||
let mut request = ClientBuilder::new().user_agent(UPDATER_USER_AGENT);
|
||||
if self.config.dangerous_accept_invalid_certs {
|
||||
if self.context.config.dangerous_accept_invalid_certs {
|
||||
request = request.danger_accept_invalid_certs(true);
|
||||
}
|
||||
if self.config.dangerous_accept_invalid_hostnames {
|
||||
if self.context.config.dangerous_accept_invalid_hostnames {
|
||||
request = request.danger_accept_invalid_hostnames(true);
|
||||
}
|
||||
if let Some(timeout) = self.timeout {
|
||||
@@ -467,7 +513,7 @@ impl Updater {
|
||||
request = request.proxy(proxy);
|
||||
}
|
||||
|
||||
if let Some(ref configure_client) = self.configure_client {
|
||||
if let Some(ref configure_client) = self.context.configure_client {
|
||||
request = configure_client(request);
|
||||
}
|
||||
|
||||
@@ -537,10 +583,6 @@ impl Updater {
|
||||
|
||||
let update = if should_update {
|
||||
Some(Update {
|
||||
run_on_main_thread: self.run_on_main_thread.clone(),
|
||||
config: self.config.clone(),
|
||||
on_before_exit: self.on_before_exit.clone(),
|
||||
app_name: self.app_name.clone(),
|
||||
current_version: self.current_version.to_string(),
|
||||
target: target.to_owned(),
|
||||
extract_path: self.extract_path.clone(),
|
||||
@@ -554,9 +596,7 @@ impl Updater {
|
||||
proxy: self.proxy.clone(),
|
||||
no_proxy: self.no_proxy,
|
||||
headers: self.headers.clone(),
|
||||
installer_args: self.installer_args.clone(),
|
||||
current_exe_args: self.current_exe_args.clone(),
|
||||
configure_client: self.configure_client.clone(),
|
||||
context: self.context.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -600,11 +640,6 @@ impl Updater {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Update {
|
||||
#[allow(dead_code)]
|
||||
run_on_main_thread: Arc<RunOnMainThread>,
|
||||
config: Config,
|
||||
#[allow(unused)]
|
||||
on_before_exit: Option<OnBeforeExit>,
|
||||
/// Update description
|
||||
pub body: Option<String>,
|
||||
/// Version used to check for update
|
||||
@@ -633,14 +668,7 @@ pub struct Update {
|
||||
/// Extract path
|
||||
#[allow(unused)]
|
||||
extract_path: PathBuf,
|
||||
/// App name, used for creating named tempfiles on Windows
|
||||
#[allow(unused)]
|
||||
app_name: String,
|
||||
#[allow(unused)]
|
||||
installer_args: Vec<OsString>,
|
||||
#[allow(unused)]
|
||||
current_exe_args: Vec<OsString>,
|
||||
configure_client: Option<OnBeforeRequest>,
|
||||
context: UpdaterContext,
|
||||
}
|
||||
|
||||
impl Resource for Update {}
|
||||
@@ -661,10 +689,10 @@ impl Update {
|
||||
}
|
||||
|
||||
let mut request = ClientBuilder::new().user_agent(UPDATER_USER_AGENT);
|
||||
if self.config.dangerous_accept_invalid_certs {
|
||||
if self.context.config.dangerous_accept_invalid_certs {
|
||||
request = request.danger_accept_invalid_certs(true);
|
||||
}
|
||||
if self.config.dangerous_accept_invalid_hostnames {
|
||||
if self.context.config.dangerous_accept_invalid_hostnames {
|
||||
request = request.danger_accept_invalid_hostnames(true);
|
||||
}
|
||||
if let Some(timeout) = self.timeout {
|
||||
@@ -676,7 +704,7 @@ impl Update {
|
||||
let proxy = reqwest::Proxy::all(proxy.as_str())?;
|
||||
request = request.proxy(proxy);
|
||||
}
|
||||
if let Some(ref configure_client) = self.configure_client {
|
||||
if let Some(ref configure_client) = self.context.configure_client {
|
||||
request = configure_client(request);
|
||||
}
|
||||
let response = request
|
||||
@@ -709,7 +737,7 @@ impl Update {
|
||||
}
|
||||
on_download_finish();
|
||||
|
||||
verify_signature(&buffer, &self.signature, &self.config.pubkey)?;
|
||||
verify_signature(&buffer, &self.signature, &self.context.config.pubkey)?;
|
||||
|
||||
Ok(buffer)
|
||||
}
|
||||
@@ -733,6 +761,16 @@ impl Update {
|
||||
fn install_inner(&self, _bytes: &[u8]) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether the Windows installer should restart the app after installed, default is `true`
|
||||
#[cfg_attr(not(windows), allow(unused))]
|
||||
pub fn restart_after_install(mut self, restart_after_install: bool) -> Self {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
self.context.restart_after_install = restart_after_install;
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -785,7 +823,6 @@ impl Update {
|
||||
/// │ └──[AppName]_[version]_x64-setup.exe # NSIS installer
|
||||
/// └── ...
|
||||
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
||||
use std::iter::once;
|
||||
use windows_sys::{
|
||||
w,
|
||||
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW},
|
||||
@@ -793,48 +830,7 @@ impl Update {
|
||||
|
||||
let updater_type = self.extract(bytes)?;
|
||||
|
||||
let install_mode = self.config.install_mode();
|
||||
let current_args = &self.current_exe_args()[1..];
|
||||
let msi_args;
|
||||
let nsis_args;
|
||||
|
||||
let installer_args: Vec<&OsStr> = match &updater_type {
|
||||
WindowsUpdaterType::Nsis { .. } => {
|
||||
nsis_args = current_args
|
||||
.iter()
|
||||
.map(escape_nsis_current_exe_arg)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
install_mode
|
||||
.nsis_args()
|
||||
.iter()
|
||||
.map(OsStr::new)
|
||||
.chain(once(OsStr::new("/UPDATE")))
|
||||
.chain(once(OsStr::new("/ARGS")))
|
||||
.chain(nsis_args.iter().map(OsStr::new))
|
||||
.chain(self.installer_args())
|
||||
.collect()
|
||||
}
|
||||
WindowsUpdaterType::Msi { path, .. } => {
|
||||
let escaped_args = current_args
|
||||
.iter()
|
||||
.map(escape_msi_property_arg)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
msi_args = OsString::from(format!("LAUNCHAPPARGS=\"{escaped_args}\""));
|
||||
|
||||
[OsStr::new("/i"), path.as_os_str()]
|
||||
.into_iter()
|
||||
.chain(install_mode.msiexec_args().iter().map(OsStr::new))
|
||||
.chain(once(OsStr::new("/promptrestart")))
|
||||
.chain(self.installer_args())
|
||||
.chain(once(OsStr::new("AUTOLAUNCHAPP=True")))
|
||||
.chain(once(msi_args.as_os_str()))
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(on_before_exit) = self.on_before_exit.as_ref() {
|
||||
if let Some(on_before_exit) = self.context.on_before_exit.as_ref() {
|
||||
log::debug!("running on_before_exit hook");
|
||||
on_before_exit();
|
||||
}
|
||||
@@ -846,9 +842,11 @@ impl Update {
|
||||
|p| OsString::from(format!("{p}\\System32\\msiexec.exe")),
|
||||
),
|
||||
};
|
||||
let file = encode_wide(file);
|
||||
let parameters = self.updater_parameters(&updater_type);
|
||||
|
||||
let parameters = installer_args.join(OsStr::new(" "));
|
||||
log::debug!("Executing updater {file:?} with parameters: {parameters:?}");
|
||||
|
||||
let file = encode_wide(file);
|
||||
let parameters = encode_wide(parameters);
|
||||
|
||||
unsafe {
|
||||
@@ -865,18 +863,72 @@ impl Update {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
fn installer_args(&self) -> Vec<&OsStr> {
|
||||
self.installer_args
|
||||
.iter()
|
||||
.map(OsStr::new)
|
||||
.collect::<Vec<_>>()
|
||||
fn updater_parameters(&self, updater_type: &WindowsUpdaterType) -> OsString {
|
||||
let install_mode = self.context.config.install_mode();
|
||||
let current_args = &self.context.current_exe_args[1..];
|
||||
|
||||
match updater_type {
|
||||
WindowsUpdaterType::Nsis { .. } => {
|
||||
let mut installer_args: Vec<&OsStr> = Vec::new();
|
||||
installer_args.extend(install_mode.nsis_args().iter().map(OsStr::new));
|
||||
installer_args.push(OsStr::new("/UPDATE"));
|
||||
|
||||
let nsis_current_exe_arg;
|
||||
if self.context.restart_after_install {
|
||||
nsis_current_exe_arg = current_args
|
||||
.iter()
|
||||
.map(escape_nsis_current_exe_arg)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
installer_args.extend(
|
||||
install_mode
|
||||
.nsis_restart_after_install_args()
|
||||
.iter()
|
||||
.map(OsStr::new),
|
||||
);
|
||||
installer_args.push(OsStr::new("/ARGS"));
|
||||
installer_args.extend(nsis_current_exe_arg.iter().map(OsStr::new));
|
||||
}
|
||||
|
||||
installer_args.extend(self.installer_args());
|
||||
|
||||
installer_args.join(OsStr::new(" "))
|
||||
}
|
||||
WindowsUpdaterType::Msi { path, .. } => {
|
||||
let mut installer_args: Vec<&OsStr> = vec![OsStr::new("/i"), path.as_os_str()];
|
||||
installer_args.extend(install_mode.msiexec_args().iter().map(OsStr::new));
|
||||
installer_args.push(OsStr::new("/promptrestart"));
|
||||
installer_args.extend(self.installer_args());
|
||||
|
||||
let msi_current_exe_arg;
|
||||
if self.context.restart_after_install {
|
||||
msi_current_exe_arg = format!(
|
||||
"LAUNCHAPPARGS=\"{}\"",
|
||||
current_args
|
||||
.iter()
|
||||
.map(escape_msi_property_arg)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
);
|
||||
|
||||
installer_args.extend(
|
||||
install_mode
|
||||
.msi_restart_after_install_args()
|
||||
.iter()
|
||||
.map(OsStr::new),
|
||||
);
|
||||
installer_args.push(OsStr::new(&msi_current_exe_arg));
|
||||
}
|
||||
|
||||
installer_args.join(OsStr::new(" "))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn current_exe_args(&self) -> Vec<&OsStr> {
|
||||
self.current_exe_args
|
||||
.iter()
|
||||
.map(OsStr::new)
|
||||
.collect::<Vec<_>>()
|
||||
fn installer_args(
|
||||
&self,
|
||||
) -> std::iter::Map<std::slice::Iter<'_, OsString>, fn(&OsString) -> &OsStr> {
|
||||
self.context.installer_args.iter().map(OsStr::new)
|
||||
}
|
||||
|
||||
fn extract(&self, bytes: &[u8]) -> Result<WindowsUpdaterType> {
|
||||
@@ -890,7 +942,10 @@ impl Update {
|
||||
|
||||
fn make_temp_dir(&self) -> Result<PathBuf> {
|
||||
Ok(tempfile::Builder::new()
|
||||
.prefix(&format!("{}-{}-updater-", self.app_name, self.version))
|
||||
.prefix(&format!(
|
||||
"{}-{}-updater-",
|
||||
self.context.app_name, self.version
|
||||
))
|
||||
.tempdir()?
|
||||
.keep())
|
||||
}
|
||||
@@ -938,7 +993,10 @@ impl Update {
|
||||
|
||||
let temp_dir = self.make_temp_dir()?;
|
||||
let mut temp_file = tempfile::Builder::new()
|
||||
.prefix(&format!("{}-{}-installer", self.app_name, self.version))
|
||||
.prefix(&format!(
|
||||
"{}-{}-installer",
|
||||
self.context.app_name, self.version
|
||||
))
|
||||
.suffix(ext)
|
||||
.rand_bytes(0)
|
||||
.tempfile_in(temp_dir)?;
|
||||
@@ -1277,7 +1335,7 @@ impl Update {
|
||||
);
|
||||
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let res = (self.run_on_main_thread)(Box::new(move || {
|
||||
let res = (self.context.run_on_main_thread)(Box::new(move || {
|
||||
let mut script =
|
||||
osakit::Script::new_from_source(osakit::Language::AppleScript, &apple_script);
|
||||
script.compile().expect("invalid AppleScript");
|
||||
@@ -1450,7 +1508,7 @@ where
|
||||
}
|
||||
|
||||
// Validate signature
|
||||
fn verify_signature(data: &[u8], release_signature: &str, pub_key: &str) -> Result<bool> {
|
||||
fn verify_signature(data: &[u8], release_signature: &str, pub_key: &str) -> Result<()> {
|
||||
// we need to convert the pub key
|
||||
let pub_key_decoded = base64_to_string(pub_key)?;
|
||||
let public_key = PublicKey::decode(&pub_key_decoded)?;
|
||||
@@ -1459,7 +1517,7 @@ fn verify_signature(data: &[u8], release_signature: &str, pub_key: &str) -> Resu
|
||||
|
||||
// Validate signature or bail out
|
||||
public_key.verify(data, &signature, true)?;
|
||||
Ok(true)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn base64_to_string(base64_string: &str) -> Result<String> {
|
||||
@@ -1498,25 +1556,31 @@ impl PathExt for PathBuf {
|
||||
|
||||
// adapted from https://github.com/rust-lang/rust/blob/1c047506f94cd2d05228eb992b0a6bbed1942349/library/std/src/sys/args/windows.rs#L174
|
||||
#[cfg(windows)]
|
||||
fn escape_nsis_current_exe_arg(arg: &&OsStr) -> String {
|
||||
let arg = arg.to_string_lossy();
|
||||
let mut cmd: Vec<char> = Vec::new();
|
||||
fn escape_nsis_current_exe_arg(arg: impl AsRef<OsStr>) -> OsString {
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
|
||||
let arg = arg.as_ref();
|
||||
let mut cmd: Vec<u16> = Vec::new();
|
||||
|
||||
// compared to std we additionally escape `/` so that nsis won't interpret them as a beginning of an nsis argument.
|
||||
let quote = arg.chars().any(|c| c == ' ' || c == '\t' || c == '/') || arg.is_empty();
|
||||
let quote = arg
|
||||
.as_encoded_bytes()
|
||||
.iter()
|
||||
.any(|c| *c == b' ' || *c == b'\t' || *c == b'/')
|
||||
|| arg.is_empty();
|
||||
let escape = true;
|
||||
if quote {
|
||||
cmd.push('"');
|
||||
cmd.push('"' as u16);
|
||||
}
|
||||
let mut backslashes: usize = 0;
|
||||
for x in arg.chars() {
|
||||
for x in arg.encode_wide() {
|
||||
if escape {
|
||||
if x == '\\' {
|
||||
if x == '\\' as u16 {
|
||||
backslashes += 1;
|
||||
} else {
|
||||
if x == '"' {
|
||||
if x == '"' as u16 {
|
||||
// Add n+1 backslashes to total 2n+1 before internal '"'.
|
||||
cmd.extend((0..=backslashes).map(|_| '\\'));
|
||||
cmd.extend((0..=backslashes).map(|_| '\\' as u16));
|
||||
}
|
||||
backslashes = 0;
|
||||
}
|
||||
@@ -1525,10 +1589,10 @@ fn escape_nsis_current_exe_arg(arg: &&OsStr) -> String {
|
||||
}
|
||||
if quote {
|
||||
// Add n backslashes to total 2n before ending '"'.
|
||||
cmd.extend((0..backslashes).map(|_| '\\'));
|
||||
cmd.push('"');
|
||||
cmd.extend((0..backslashes).map(|_| '\\' as u16));
|
||||
cmd.push('"' as u16);
|
||||
}
|
||||
cmd.into_iter().collect()
|
||||
OsString::from_wide(&cmd)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
"endpoints": ["http://localhost:3007"],
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUwNDRGMjkwRjg2MDhCRDAKUldUUWkyRDRrUEpFNEQ4SmdwcU5PaXl6R2ZRUUNvUnhIaVkwVUltV0NMaEx6VTkrWVhpT0ZqeEEK",
|
||||
"windows": {
|
||||
"installMode": "quiet",
|
||||
"installerArgs": ["/NS"]
|
||||
"installMode": "quiet"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -46,7 +46,7 @@ struct Update {
|
||||
platforms: HashMap<String, PlatformUpdate>,
|
||||
}
|
||||
|
||||
fn build_app(cwd: &Path, config: &Config, bundle_updater: bool, target: BundleTarget) {
|
||||
fn build_app(cwd: &Path, config: &Config, target: Option<BundleTarget>) {
|
||||
let mut command = Command::new("cargo");
|
||||
command
|
||||
.args(["tauri", "build", "--verbose"])
|
||||
@@ -56,17 +56,10 @@ fn build_app(cwd: &Path, config: &Config, bundle_updater: bool, target: BundleTa
|
||||
.env("TAURI_SIGNING_PRIVATE_KEY_PASSWORD", "")
|
||||
.current_dir(cwd);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
command.args(["--bundles", target.name()]);
|
||||
#[cfg(target_os = "macos")]
|
||||
command.args(["--bundles", target.name()]);
|
||||
|
||||
if bundle_updater {
|
||||
#[cfg(windows)]
|
||||
command.args(["--bundles", "msi", "nsis"]);
|
||||
if let Some(target) = target {
|
||||
command.arg("--bundles").arg(target.name());
|
||||
} else {
|
||||
#[cfg(windows)]
|
||||
command.args(["--bundles", target.name()]);
|
||||
command.arg("--no-bundle");
|
||||
}
|
||||
|
||||
let status = command
|
||||
@@ -318,7 +311,7 @@ fn update_app() {
|
||||
{
|
||||
// bundle app update
|
||||
config.version = "1.0.0";
|
||||
build_app(&manifest_dir, &config, true, BundleTarget::default());
|
||||
build_app(&manifest_dir, &config, Some(bundle_target));
|
||||
|
||||
let bundle_updater_ext = if v1_compatible {
|
||||
out_bundle_path
|
||||
@@ -401,7 +394,7 @@ fn update_app() {
|
||||
config.version = "0.1.0";
|
||||
|
||||
// bundle initial app version
|
||||
build_app(&manifest_dir, &config, false, bundle_target);
|
||||
build_app(&manifest_dir, &config, None);
|
||||
|
||||
for expected_exit_code in status_checks {
|
||||
let mut binary_cmd = if cfg!(windows) {
|
||||
|
||||
+9
-10
@@ -1822,15 +1822,14 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.78"
|
||||
version = "0.10.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222"
|
||||
checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
@@ -1854,9 +1853,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.114"
|
||||
version = "0.9.116"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6"
|
||||
checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -2951,9 +2950,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.45"
|
||||
version = "0.4.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
|
||||
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
@@ -3795,7 +3794,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4138,9 +4137,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.24.10"
|
||||
version = "0.24.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00711278ed357350d44c749c286786ecac644e044e4da410d466212152383b45"
|
||||
checksum = "4a2a144c3ab5e83e04724bc8e67cea552ffae413185fda459fafdae173fd985d"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"block",
|
||||
|
||||
@@ -66,7 +66,8 @@ import { upload, HttpMethod } from '@tauri-apps/plugin-upload'
|
||||
upload(
|
||||
'https://example.com/file-upload',
|
||||
'./path/to/my/file.txt',
|
||||
(progress, total) => console.log(`Uploaded ${progress} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||
({ progressTotal, total }) =>
|
||||
console.log(`Uploaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
)
|
||||
|
||||
@@ -74,7 +75,8 @@ upload(
|
||||
upload(
|
||||
'https://example.com/file-upload',
|
||||
'./path/to/my/file.txt',
|
||||
(progress, total) => console.log(`Uploaded ${progress} of ${total} bytes`),
|
||||
({ progressTotal, total }) =>
|
||||
console.log(`Uploaded ${progressTotal} of ${total} bytes`),
|
||||
{ 'Content-Type': 'text/plain' },
|
||||
HttpMethod.Put // Use HttpMethod enum - supports POST, PUT, PATCH
|
||||
)
|
||||
@@ -86,7 +88,8 @@ import { download } from '@tauri-apps/plugin-upload'
|
||||
download(
|
||||
'https://example.com/file-download-link',
|
||||
'./path/to/save/my/file.txt',
|
||||
(progress, total) => console.log(`Downloaded ${progress} of ${total} bytes`), // a callback that will be called with the download progress
|
||||
({ progressTotal, total }) =>
|
||||
console.log(`Downloaded ${progressTotal} of ${total} bytes`), // a callback that will be called with the download progress
|
||||
{ 'Content-Type': 'text/plain' } // optional headers to send with the request
|
||||
)
|
||||
```
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"@tauri-apps/cli": "2.11.4",
|
||||
"typescript": "^6.0.0",
|
||||
"vite": "^8.0.1"
|
||||
},
|
||||
|
||||
@@ -452,47 +452,47 @@ impl Builder {
|
||||
}
|
||||
}
|
||||
|
||||
WindowEvent::Moved(position) if state_flags.contains(StateFlags::POSITION) => {
|
||||
if window_clone
|
||||
.state::<RestoringWindowState>()
|
||||
.0
|
||||
.try_lock()
|
||||
.is_ok()
|
||||
&& !window_clone.is_minimized().unwrap_or_default()
|
||||
{
|
||||
let mut c = cache.lock().unwrap();
|
||||
if let Some(state) = c.get_mut(&label) {
|
||||
state.prev_x = state.x;
|
||||
state.prev_y = state.y;
|
||||
WindowEvent::Moved(position)
|
||||
if state_flags.contains(StateFlags::POSITION)
|
||||
&& window_clone
|
||||
.state::<RestoringWindowState>()
|
||||
.0
|
||||
.try_lock()
|
||||
.is_ok()
|
||||
&& !window_clone.is_minimized().unwrap_or_default() =>
|
||||
{
|
||||
let mut c = cache.lock().unwrap();
|
||||
if let Some(state) = c.get_mut(&label) {
|
||||
state.prev_x = state.x;
|
||||
state.prev_y = state.y;
|
||||
|
||||
state.x = position.x;
|
||||
state.y = position.y;
|
||||
}
|
||||
state.x = position.x;
|
||||
state.y = position.y;
|
||||
}
|
||||
}
|
||||
WindowEvent::Resized(size) if state_flags.contains(StateFlags::SIZE) => {
|
||||
if window_clone
|
||||
.state::<RestoringWindowState>()
|
||||
.0
|
||||
.try_lock()
|
||||
.is_ok()
|
||||
WindowEvent::Resized(size)
|
||||
if state_flags.contains(StateFlags::SIZE)
|
||||
&& window_clone
|
||||
.state::<RestoringWindowState>()
|
||||
.0
|
||||
.try_lock()
|
||||
.is_ok() =>
|
||||
{
|
||||
// TODO: Remove once https://github.com/tauri-apps/tauri/issues/5812 is resolved.
|
||||
let is_maximized = if cfg!(target_os = "macos")
|
||||
&& (!window_clone.is_decorated().unwrap_or_default()
|
||||
|| !window_clone.is_resizable().unwrap_or_default())
|
||||
{
|
||||
// TODO: Remove once https://github.com/tauri-apps/tauri/issues/5812 is resolved.
|
||||
let is_maximized = if cfg!(target_os = "macos")
|
||||
&& (!window_clone.is_decorated().unwrap_or_default()
|
||||
|| !window_clone.is_resizable().unwrap_or_default())
|
||||
{
|
||||
false
|
||||
} else {
|
||||
window_clone.is_maximized().unwrap_or_default()
|
||||
};
|
||||
false
|
||||
} else {
|
||||
window_clone.is_maximized().unwrap_or_default()
|
||||
};
|
||||
|
||||
if !window_clone.is_minimized().unwrap_or_default() && !is_maximized {
|
||||
let mut c = cache.lock().unwrap();
|
||||
if let Some(state) = c.get_mut(&label) {
|
||||
state.width = size.width;
|
||||
state.height = size.height;
|
||||
}
|
||||
if !window_clone.is_minimized().unwrap_or_default() && !is_maximized {
|
||||
let mut c = cache.lock().unwrap();
|
||||
if let Some(state) = c.get_mut(&label) {
|
||||
state.width = size.width;
|
||||
state.height = size.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+551
-549
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user