mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-05-01 12:08:06 +02:00
Compare commits
267 Commits
shell-v2.3.0
...
v2
| Author | SHA1 | Date | |
|---|---|---|---|
| b86e999beb | |||
| c463d8ab14 | |||
| 1bb7beb307 | |||
| 3412fa2741 | |||
| af81fdac98 | |||
| c1fd33b3a2 | |||
| 250857b7b7 | |||
| 964e13f124 | |||
| e6cdc9f52e | |||
| 9228419e13 | |||
| 04d92139c8 | |||
| 5260fc90b0 | |||
| ea5c70060b | |||
| d016a8ab1e | |||
| d6a3898001 | |||
| 2e5bcdf202 | |||
| 4374b4fc1a | |||
| f75d21db33 | |||
| 4b95f5e079 | |||
| 99c3e37b54 | |||
| eaac19a5b7 | |||
| 5183e314cb | |||
| 2c0883e64e | |||
| 024ec0c29c | |||
| 35aad24773 | |||
| ab037b70d6 | |||
| 1198ad4fb0 | |||
| ea033fe3b8 | |||
| 2e432f70c9 | |||
| b19dcd25cb | |||
| 995e76436f | |||
| 1dc3612862 | |||
| f5f68063e4 | |||
| 36d3d19247 | |||
| 31ab6f8d24 | |||
| 21ae430ea3 | |||
| 015e817cf2 | |||
| 2a6d4b42bb | |||
| 550d137c64 | |||
| 3f21f39584 | |||
| 759c22758e | |||
| 6816dd1960 | |||
| 24154472a6 | |||
| 2574ec89e7 | |||
| 2971289252 | |||
| 6c3da6d290 | |||
| e97a4dedab | |||
| 05045f9a72 | |||
| 4f53e36a50 | |||
| 8374e997b8 | |||
| 35aa52f45e | |||
| bbc177150f | |||
| e6e2edca11 | |||
| 7ecd19da51 | |||
| a0b6c8ff3b | |||
| c12ea9306a | |||
| 98e2c11eef | |||
| 50b159f668 | |||
| 305c4f6b4e | |||
| 89f3e17952 | |||
| d4613ff002 | |||
| 69a9d5771c | |||
| 61e9b0ab64 | |||
| 25ad21beff | |||
| 2dc3f3f039 | |||
| c27af9128d | |||
| b60dd88702 | |||
| a97033bcd9 | |||
| 4375c98bed | |||
| 82fbb0c790 | |||
| de6bf68585 | |||
| 734c627084 | |||
| 05c5da072b | |||
| 0d126ff0ad | |||
| f122ee98c6 | |||
| 2308f2299d | |||
| 82c404635b | |||
| b1dbee2c55 | |||
| d7a0bb325d | |||
| f3d75f7abb | |||
| 6e2e7e48c3 | |||
| 9a2c98f450 | |||
| 4a2ecb6287 | |||
| 31415effdf | |||
| 04b33ea0b0 | |||
| 54e21f142b | |||
| d528c88b4f | |||
| 69146fa852 | |||
| 9f68f2d827 | |||
| 3d0d2e041b | |||
| 1e3d7ef16e | |||
| ce6835d50f | |||
| 1d9f47c882 | |||
| e221a04ef4 | |||
| eebfd2ed3e | |||
| 521cd8b372 | |||
| e4a40f4423 | |||
| fa8b11f19d | |||
| baefd761e0 | |||
| 2804803949 | |||
| d9d51eb8ea | |||
| 1483c63101 | |||
| 26ed78989a | |||
| f1564e58b6 | |||
| f2d4abb9e2 | |||
| 3dcf7522b1 | |||
| 02068550e8 | |||
| 66a75ece27 | |||
| fa601e8754 | |||
| d8bfe61f20 | |||
| e8915f17e4 | |||
| 6de61f854b | |||
| ad7a8d3e42 | |||
| d5509a9ac8 | |||
| 06727b19c1 | |||
| 2f9fa79747 | |||
| 1db4b0719d | |||
| dff6fa986a | |||
| a4aa53ab90 | |||
| ae278ddf60 | |||
| e644f38673 | |||
| 8bfa445023 | |||
| 14fb36e347 | |||
| 5767b848fa | |||
| 277a45f56c | |||
| 8dbe7e3233 | |||
| c23fa03f07 | |||
| 631d0e256a | |||
| b4348cee92 | |||
| 3019063ae1 | |||
| 944614f46a | |||
| a368cef912 | |||
| 27790aa67c | |||
| ad910b1135 | |||
| 6b854421a1 | |||
| 5438a5cd22 | |||
| 5cd7778723 | |||
| 1a03e9761f | |||
| 1d4bffadda | |||
| b8794272ae | |||
| 2a625adff3 | |||
| 371cd8227c | |||
| 70ef6f8d3e | |||
| 5f0ac1436f | |||
| ea172bfa3c | |||
| 6aead24047 | |||
| e7a68fa637 | |||
| b5550a3b0d | |||
| 93426f8512 | |||
| 4ee61e055e | |||
| 06124af8d6 | |||
| 060219e597 | |||
| c7e9766ff5 | |||
| d4a8ce962b | |||
| cdc7eec415 | |||
| 6314b004ab | |||
| fb4c8ae54c | |||
| fccc1cfb7e | |||
| 3702308e6f | |||
| c9c8b39b56 | |||
| 3c396feedf | |||
| b514d482fa | |||
| 60e5714ceb | |||
| 654bf4891a | |||
| 6c9b61fb65 | |||
| 6b5b1053ba | |||
| 67a7bf80f8 | |||
| e25a9339f4 | |||
| 92f98a93b4 | |||
| c0f82e5a5e | |||
| 5204145c6a | |||
| b4ee33dd01 | |||
| e933acb004 | |||
| e4a9154f4a | |||
| d44ac9afed | |||
| 1b197c2d4d | |||
| 650ff5ff23 | |||
| 2930aa39a4 | |||
| 3e92ce260b | |||
| 12da195fce | |||
| 30dd109d9f | |||
| 5e5bc30ad0 | |||
| f6dca71343 | |||
| 021e573248 | |||
| 51b430be98 | |||
| fd439b143e | |||
| 2522b71f6b | |||
| 9021a73247 | |||
| 625bb1c096 | |||
| 6215afe023 | |||
| 8cf8eeab02 | |||
| 509eba8d44 | |||
| 9ac5fe84e7 | |||
| c247410319 | |||
| de45034082 | |||
| 50c6b7c644 | |||
| b79d02d896 | |||
| b75f9f5cd3 | |||
| d865ed4768 | |||
| 1107c46425 | |||
| 23a3705857 | |||
| 6f65e68340 | |||
| 1a0b791650 | |||
| 2d03e2eac2 | |||
| 21d721a0c2 | |||
| 8abb31ee59 | |||
| 0354046817 | |||
| 04a0954857 | |||
| 9e4e859bea | |||
| 2371804172 | |||
| 90f9b9310a | |||
| 1c58f3372c | |||
| 75617a6a92 | |||
| 5a963a0496 | |||
| 76f4e7bb84 | |||
| 670ac1d7c1 | |||
| ed0deef2cf | |||
| 50cebdb6d5 | |||
| dd2ea9cfa5 | |||
| 515182a179 | |||
| d3d290ab8a | |||
| b51c827b2c | |||
| a4b71a1992 | |||
| 4eb36b0ff5 | |||
| b8056f484c | |||
| 5ac8fbb1fa | |||
| e0323ec752 | |||
| cc98e6a892 | |||
| af22ae0a97 | |||
| 2f24c7a70c | |||
| fe23a5e013 | |||
| ff6d23ede1 | |||
| 449dd117a4 | |||
| 9b43f48856 | |||
| af08c66faa | |||
| 7974acae22 | |||
| a985359e69 | |||
| 97bebcf6e8 | |||
| 27ddcd0abe | |||
| d7fb5623d6 | |||
| d4f8299b12 | |||
| 341919ed57 | |||
| 124f2191aa | |||
| 0970b94949 | |||
| 7340242d4e | |||
| d66aa6ff78 | |||
| 6f345870df | |||
| 708fa4e2b7 | |||
| b729203059 | |||
| 2f9c71aae7 | |||
| 80d4d8e128 | |||
| e7a98b0d2e | |||
| 44a1f65912 | |||
| 6210cd31df | |||
| 467f07b7de | |||
| 7ba6e08a86 | |||
| 989470f0d7 | |||
| ca3c3aa28a | |||
| aa9140e1ac | |||
| 6a8f255878 | |||
| 8ac494da7c | |||
| 1635282868 | |||
| 4587e4a2b3 | |||
| 1135dc7ed3 | |||
| fe01894e7f | |||
| 36400b5678 | |||
| ead3c268e1 |
+4
-8
@@ -1,11 +1,7 @@
|
||||
[advisories]
|
||||
ignore = [
|
||||
# time 0.1
|
||||
"RUSTSEC-2020-0071",
|
||||
# needs sqlx 0.7 (still in alpha)
|
||||
"RUSTSEC-2022-0090",
|
||||
# wry needs kuchiki on Android
|
||||
"RUSTSEC-2023-0019",
|
||||
# atty is only used when the `colored` feature is enabled on tauri-plugin-log
|
||||
"RUSTSEC-2021-0145",
|
||||
# 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",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
deep-link: patch
|
||||
deep-link-js: patch
|
||||
---
|
||||
|
||||
Fix broken iOS custom URL schemes
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"opener": patch
|
||||
"opener-js": patch
|
||||
---
|
||||
|
||||
Fix `revealItemInDir`/`reveal_items_in_dir` can't reveal network paths like `\\wsl.localhost\Ubuntu\etc` on Windows
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
store: patch
|
||||
store-js: patch
|
||||
---
|
||||
|
||||
Fix a deadlock when calling `Store::set` while exiting (on `RunEvent::Exit`)
|
||||
@@ -5,6 +5,7 @@ Hi! We, the maintainers, are really excited that you are interested in contribut
|
||||
- [Issue Reporting Guidelines](#issue-reporting-guidelines)
|
||||
- [Pull Request Guidelines](#pull-request-guidelines)
|
||||
- [Development Guide](#development-guide)
|
||||
- [AI Tool Policy](#ai-tool-policy)
|
||||
|
||||
## Issue Reporting Guidelines
|
||||
|
||||
@@ -60,3 +61,13 @@ The easiest way to test your changes is to use the [example app](https://github.
|
||||
To test local changes against your own application simply point the plugin create to your local repository, for example:
|
||||
|
||||
`tauri-plugin-sample = { path = "path/to/local/tauri-plugin-sample/" }`
|
||||
|
||||
## AI Tool Policy
|
||||
|
||||
It takes a lot of time to review a Pull Request while it's very easy to make a nonsensical but plausible looking one using AI tools.
|
||||
It is unfair for other contributors and the reviewers to spend much of the time dealing with this, hence these rules:
|
||||
|
||||
1. Review and test all LLM-generated content before submitting, you're the one responsible for it, not the AI.
|
||||
2. Don't use AI to respond to review comments (except for translations).
|
||||
|
||||
We will close the Pull Request with a `ai-slop` tag if you failed to do so.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: 🐞 Bug Report
|
||||
description: Report a bug
|
||||
labels: ['type: bug']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## First of all
|
||||
1. Please search for [existing issues](https://github.com/tauri-apps/plugins-workspace/issues?q=is%3Aissue) about this problem first.
|
||||
2. Make sure `rustc` and all relevant Tauri packages are up to date.
|
||||
3. Make sure it's an issue with a tauri plugin and not something else you are using.
|
||||
4. Remember to follow our community guidelines and be friendly.
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear description of what the bug is. Include screenshots if applicable.
|
||||
placeholder: Bug description
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction
|
||||
description: A link to a reproduction repo or steps to reproduce the behaviour.
|
||||
placeholder: |
|
||||
Please provide a minimal reproduction or steps to reproduce, see this guide https://stackoverflow.com/help/minimal-reproducible-example
|
||||
Why reproduction is required? see this article https://antfu.me/posts/why-reproductions-are-required
|
||||
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear description of what you expected to happen.
|
||||
|
||||
- type: textarea
|
||||
id: info
|
||||
attributes:
|
||||
label: Full `tauri info` output
|
||||
description: 'Output of `npm run tauri info` or `cargo tauri info`. Issues without this will be closed!'
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Stack trace
|
||||
description: A stack trace or ANY error messages you may see.
|
||||
render: text
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here. For example a link to a Discord discussion.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
#blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 💡 Request a new plugin
|
||||
url: https://github.com/orgs/tauri-apps/discussions/new?category=plugin-requests
|
||||
about: Propose a new Plugin to the community or the Tauri org.
|
||||
- name: 💬 Discord Chat
|
||||
url: https://discord.com/invite/tauri
|
||||
about: Ask questions and talk to other Tauri users and the maintainers
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
name: 📚 Docs Report
|
||||
about: Create a report to help us improve the docs
|
||||
labels: 'type: documentation'
|
||||
---
|
||||
@@ -0,0 +1,46 @@
|
||||
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: 💡 Feature Request
|
||||
description: Request a feature or enhancement for an existing plugin
|
||||
labels: ['type: feature request']
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## First of all
|
||||
- Please search for [existing issues](https://github.com/tauri-apps/plugins-workspace/issues?q=is%3Aissue) for this request first.
|
||||
- Only requests for plugins that exist in this repo are allowed.
|
||||
- You can request new plugins [here](https://github.com/orgs/tauri-apps/discussions/new?category=plugin-requests)
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Describe the problem
|
||||
description: A clear description of the problem this feature would solve
|
||||
placeholder: "I'm always frustrated when..."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: "Describe the solution you'd like"
|
||||
description: A clear description of what change you would like
|
||||
placeholder: 'I would like to...'
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives considered
|
||||
description: "Any alternative solutions you've considered"
|
||||
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: rustsec/audit-check@v1
|
||||
- uses: rustsec/audit-check@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# https://github.com/tauri-apps/plugins-workspace/issues/774
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
- v2
|
||||
|
||||
permissions:
|
||||
# required for npm provenance
|
||||
# required for oidc token
|
||||
id-token: write
|
||||
# required to create the GitHub Release
|
||||
contents: write
|
||||
@@ -62,7 +62,6 @@ jobs:
|
||||
id: covector
|
||||
env:
|
||||
CARGO_TARGET_DIR: /mnt/target
|
||||
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
command: 'version-or-publish'
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
name: integration tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- v1
|
||||
|
||||
@@ -154,4 +154,5 @@ jobs:
|
||||
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
|
||||
|
||||
- name: clippy ${{ matrix.package }} --all-features
|
||||
if: matrix.package != 'tauri-plugin-dialog'
|
||||
run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
|
||||
|
||||
@@ -246,9 +246,9 @@ jobs:
|
||||
run: cargo +stable install cross --git https://github.com/cross-rs/cross
|
||||
|
||||
- name: test ${{ matrix.package }}
|
||||
if: matrix.package != 'tauri-plugin-http'
|
||||
if: ${{ matrix.package != 'tauri-plugin-http' && matrix.package != 'tauri-plugin-dialog' }}
|
||||
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
|
||||
|
||||
- name: test ${{ matrix.package }}
|
||||
if: matrix.package == 'tauri-plugin-http'
|
||||
if: ${{ matrix.package == 'tauri-plugin-http' || matrix.package == 'tauri-plugin-dialog' }}
|
||||
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ target/
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
bun.lockb
|
||||
bun.lock
|
||||
|
||||
# rust compiled folders
|
||||
target/
|
||||
@@ -58,4 +59,4 @@ pids
|
||||
.idea
|
||||
debug.log
|
||||
TODO.md
|
||||
.aider*
|
||||
.aider.*
|
||||
|
||||
Generated
+708
-647
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -12,10 +12,10 @@ resolver = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tracing = "0.1"
|
||||
log = "0.4"
|
||||
tauri = { version = "2.6", default-features = false }
|
||||
tauri-build = "2.3"
|
||||
tauri-plugin = "2.3"
|
||||
tauri-utils = "2.5"
|
||||
tauri = { version = "2.10", default-features = false }
|
||||
tauri-build = "2.5"
|
||||
tauri-plugin = "2.5"
|
||||
tauri-utils = "2.8"
|
||||
serde_json = "1"
|
||||
thiserror = "2"
|
||||
url = "2"
|
||||
@@ -23,7 +23,7 @@ schemars = "0.8"
|
||||
dunce = "1"
|
||||
specta = "^2.0.0-rc.16"
|
||||
glob = "0.3"
|
||||
zbus = "5"
|
||||
zbus = "5.9"
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
|
||||
@@ -22,7 +22,7 @@ This repo and all plugins require a Rust version of at least **1.77.2**
|
||||
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [nfc](plugins/nfc) | Read and write NFC tags on Android and iOS. | ? | ? | ? | ✅ | ✅ |
|
||||
| [notification](plugins/notification) | Send message notifications (brief auto-expiring OS window element) to your user. Can also be used with the Notification Web API. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [opener](plugins/opener) | Open files and URLs using their default application. | ✅ | ✅ | ✅ | ? | ? |
|
||||
| [opener](plugins/opener) | Open files and URLs using their default application. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [os](plugins/os) | Read information about the operating system. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
|
||||
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -33,7 +33,7 @@ This repo and all plugins require a Rust version of at least **1.77.2**
|
||||
| [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? |
|
||||
| [updater](plugins/updater) | In-app updates for Tauri applications. | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? |
|
||||
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
|
||||
| [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
|
||||
|
||||
+2
-1
@@ -3,11 +3,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import eslint from '@eslint/js'
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import eslintConfigPrettier from 'eslint-config-prettier'
|
||||
import eslintPluginSecurity from 'eslint-plugin-security'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
export default defineConfig(
|
||||
{
|
||||
ignores: [
|
||||
'**/target',
|
||||
|
||||
@@ -1,5 +1,127 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.38]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.5.0`
|
||||
- Upgraded to `http-js@2.5.8`
|
||||
- Upgraded to `updater-js@2.10.1`
|
||||
- Upgraded to `nfc-js@2.3.5`
|
||||
- Upgraded to `dialog-js@2.7.0`
|
||||
|
||||
## \[2.0.37]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `updater-js@2.10.0`
|
||||
- Upgraded to `barcode-scanner-js@2.4.4`
|
||||
- Upgraded to `http-js@2.5.7`
|
||||
- Upgraded to `shell-js@2.3.5`
|
||||
|
||||
## \[2.0.36]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `http-js@2.5.6`
|
||||
- Upgraded to `dialog-js@2.6.0`
|
||||
|
||||
## \[2.0.35]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog-js@2.5.0`
|
||||
- Upgraded to `log-js@2.8.0`
|
||||
- Upgraded to `shell-js@2.3.4`
|
||||
- Upgraded to `barcode-scanner-js@2.4.3`
|
||||
- Upgraded to `fs-js@2.4.5`
|
||||
- Upgraded to `http-js@2.5.5`
|
||||
- Upgraded to `nfc-js@2.3.4`
|
||||
- Upgraded to `opener-js@2.5.3`
|
||||
- Upgraded to `store-js@2.4.2`
|
||||
|
||||
## \[2.0.34]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner-js@2.4.2`
|
||||
- Upgraded to `biometric-js@2.3.2`
|
||||
- Upgraded to `cli-js@2.4.1`
|
||||
- Upgraded to `clipboard-manager-js@2.3.2`
|
||||
- Upgraded to `dialog-js@2.4.2`
|
||||
- Upgraded to `fs-js@2.4.4`
|
||||
- Upgraded to `global-shortcut-js@2.3.1`
|
||||
- Upgraded to `http-js@2.5.4`
|
||||
- Upgraded to `log-js@2.7.1`
|
||||
- Upgraded to `nfc-js@2.3.3`
|
||||
- Upgraded to `notification-js@2.3.3`
|
||||
- Upgraded to `opener-js@2.5.2`
|
||||
- Upgraded to `os-js@2.3.2`
|
||||
- Upgraded to `process-js@2.3.1`
|
||||
- Upgraded to `shell-js@2.3.3`
|
||||
- Upgraded to `store-js@2.4.1`
|
||||
|
||||
## \[2.0.33]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner-js@2.4.1`
|
||||
- Upgraded to `biometric-js@2.3.1`
|
||||
- Upgraded to `clipboard-manager-js@2.3.1`
|
||||
- Upgraded to `dialog-js@2.4.1`
|
||||
- Upgraded to `fs-js@2.4.3`
|
||||
- Upgraded to `nfc-js@2.3.2`
|
||||
- Upgraded to `notification-js@2.3.2`
|
||||
- Upgraded to `opener-js@2.5.1`
|
||||
- Upgraded to `shell-js@2.3.2`
|
||||
- Upgraded to `http-js@2.5.3`
|
||||
|
||||
## \[2.0.32]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog-js@2.4.0`
|
||||
- Upgraded to `log-js@2.7.0`
|
||||
|
||||
## \[2.0.31]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `shell-js@2.3.1`
|
||||
|
||||
## \[2.0.30]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `notification-js@2.3.1`
|
||||
|
||||
## \[2.0.29]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.2`
|
||||
- Upgraded to `nfc-js@2.3.1`
|
||||
- Upgraded to `opener-js@2.5.0`
|
||||
- Upgraded to `os-js@2.3.1`
|
||||
- Upgraded to `store-js@2.4.0`
|
||||
- Upgraded to `dialog-js@2.3.3`
|
||||
- Upgraded to `http-js@2.5.2`
|
||||
|
||||
## \[2.0.28]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog-js@2.3.2`
|
||||
|
||||
## \[2.0.27]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner-js@2.4.0`
|
||||
- Upgraded to `fs-js@2.4.1`
|
||||
- Upgraded to `dialog-js@2.3.1`
|
||||
- Upgraded to `http-js@2.5.1`
|
||||
|
||||
## \[2.0.26]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=0"
|
||||
/>
|
||||
<title>Svelte + Vite App</title>
|
||||
</head>
|
||||
|
||||
+28
-27
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "api",
|
||||
"private": true,
|
||||
"version": "2.0.26",
|
||||
"version": "2.0.38",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --clearScreen false",
|
||||
@@ -10,35 +10,36 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.6.0",
|
||||
"@tauri-apps/plugin-barcode-scanner": "^2.3.0",
|
||||
"@tauri-apps/plugin-biometric": "^2.3.0",
|
||||
"@tauri-apps/plugin-cli": "^2.4.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.3.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.0",
|
||||
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
||||
"@tauri-apps/plugin-global-shortcut": "^2.3.0",
|
||||
"@tauri-apps/plugin-haptics": "^2.2.0",
|
||||
"@tauri-apps/plugin-http": "^2.5.0",
|
||||
"@tauri-apps/plugin-nfc": "^2.3.0",
|
||||
"@tauri-apps/plugin-notification": "^2.3.0",
|
||||
"@tauri-apps/plugin-opener": "^2.4.0",
|
||||
"@tauri-apps/plugin-os": "^2.3.0",
|
||||
"@tauri-apps/plugin-process": "^2.3.0",
|
||||
"@tauri-apps/plugin-shell": "^2.3.0",
|
||||
"@tauri-apps/plugin-store": "^2.3.0",
|
||||
"@tauri-apps/plugin-updater": "^2.9.0",
|
||||
"@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.0",
|
||||
"@tauri-apps/plugin-fs": "^2.5.0",
|
||||
"@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.8",
|
||||
"@tauri-apps/plugin-nfc": "^2.3.5",
|
||||
"@tauri-apps/plugin-notification": "^2.3.3",
|
||||
"@tauri-apps/plugin-opener": "^2.5.3",
|
||||
"@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.2",
|
||||
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||
"@tauri-apps/plugin-upload": "^2.4.0",
|
||||
"@zerodevx/svelte-json-view": "1.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/codicon": "^1.2.12",
|
||||
"@iconify-json/codicon": "^1.2.49",
|
||||
"@iconify-json/ph": "^1.2.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@tauri-apps/cli": "2.6.0",
|
||||
"@unocss/extractor-svelte": "^66.0.0",
|
||||
"svelte": "^5.20.4",
|
||||
"unocss": "^66.0.0",
|
||||
"vite": "^6.2.6"
|
||||
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"@unocss/extractor-svelte": "^66.6.7",
|
||||
"svelte": "^5.54.0",
|
||||
"unocss": "^66.6.7",
|
||||
"vite": "^8.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,131 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.0.42]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs@2.5.0`
|
||||
- Upgraded to `http@2.5.8`
|
||||
- Upgraded to `updater@2.10.1`
|
||||
- Upgraded to `nfc@2.3.5`
|
||||
- Upgraded to `dialog@2.7.0`
|
||||
|
||||
## \[2.0.41]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `updater@2.10.0`
|
||||
- Upgraded to `barcode-scanner@2.4.4`
|
||||
- Upgraded to `http@2.5.7`
|
||||
- Upgraded to `shell@2.3.5`
|
||||
|
||||
## \[2.0.40]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `http@2.5.6`
|
||||
- Upgraded to `dialog@2.6.0`
|
||||
|
||||
## \[2.0.39]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog@2.5.0`
|
||||
- Upgraded to `log@2.8.0`
|
||||
- Upgraded to `shell@2.3.4`
|
||||
- Upgraded to `barcode-scanner@2.4.3`
|
||||
- Upgraded to `fs@2.4.5`
|
||||
- Upgraded to `http@2.5.5`
|
||||
- Upgraded to `nfc@2.3.4`
|
||||
- Upgraded to `opener@2.5.3`
|
||||
- Upgraded to `store@2.4.2`
|
||||
|
||||
## \[2.0.38]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner@2.4.2`
|
||||
- Upgraded to `biometric@2.3.2`
|
||||
- Upgraded to `cli@2.4.1`
|
||||
- Upgraded to `clipboard-manager@2.3.2`
|
||||
- Upgraded to `dialog@2.4.2`
|
||||
- Upgraded to `fs@2.4.4`
|
||||
- Upgraded to `geolocation@2.3.2`
|
||||
- Upgraded to `global-shortcut@2.3.1`
|
||||
- Upgraded to `haptics@2.3.2`
|
||||
- Upgraded to `http@2.5.4`
|
||||
- Upgraded to `log@2.7.1`
|
||||
- Upgraded to `nfc@2.3.3`
|
||||
- Upgraded to `notification@2.3.3`
|
||||
- Upgraded to `opener@2.5.2`
|
||||
- Upgraded to `os@2.3.2`
|
||||
- Upgraded to `process@2.3.1`
|
||||
- Upgraded to `shell@2.3.3`
|
||||
- Upgraded to `store@2.4.1`
|
||||
|
||||
## \[2.0.37]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner@2.4.1`
|
||||
- Upgraded to `biometric@2.3.1`
|
||||
- Upgraded to `clipboard-manager@2.3.1`
|
||||
- Upgraded to `dialog@2.4.1`
|
||||
- Upgraded to `fs@2.4.3`
|
||||
- Upgraded to `geolocation@2.3.1`
|
||||
- Upgraded to `haptics@2.3.1`
|
||||
- Upgraded to `nfc@2.3.2`
|
||||
- Upgraded to `notification@2.3.2`
|
||||
- Upgraded to `opener@2.5.1`
|
||||
- Upgraded to `shell@2.3.2`
|
||||
- Upgraded to `http@2.5.3`
|
||||
|
||||
## \[2.0.36]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog@2.4.0`
|
||||
- Upgraded to `log@2.7.0`
|
||||
|
||||
## \[2.0.35]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `shell@2.3.1`
|
||||
|
||||
## \[2.0.34]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `notification@2.3.1`
|
||||
|
||||
## \[2.0.33]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs@2.4.2`
|
||||
- Upgraded to `nfc@2.3.1`
|
||||
- Upgraded to `opener@2.5.0`
|
||||
- Upgraded to `os@2.3.1`
|
||||
- Upgraded to `store@2.4.0`
|
||||
- Upgraded to `dialog@2.3.3`
|
||||
- Upgraded to `http@2.5.2`
|
||||
|
||||
## \[2.0.32]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `dialog@2.3.2`
|
||||
|
||||
## \[2.0.31]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `barcode-scanner@2.4.0`
|
||||
- Upgraded to `fs@2.4.1`
|
||||
- Upgraded to `dialog@2.3.1`
|
||||
- Upgraded to `http@2.5.1`
|
||||
|
||||
## \[2.0.30]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "api"
|
||||
publish = false
|
||||
version = "2.0.30"
|
||||
version = "2.0.42"
|
||||
description = "An example Tauri Application showcasing the api"
|
||||
edition = "2021"
|
||||
rust-version = { workspace = true }
|
||||
@@ -20,24 +20,25 @@ serde = { workspace = true }
|
||||
tiny_http = "0.12"
|
||||
time = "0.3"
|
||||
log = { workspace = true }
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.6.0" }
|
||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.0", features = [
|
||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.8.0" }
|
||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.5.0", features = [
|
||||
"watch",
|
||||
] }
|
||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.0" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.3.0" }
|
||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.2" }
|
||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.7.0" }
|
||||
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
||||
"multipart",
|
||||
"cookies",
|
||||
], version = "2.5.0" }
|
||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.0", features = [
|
||||
], version = "2.5.8" }
|
||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.3", features = [
|
||||
"windows7-compat",
|
||||
] }
|
||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.0" }
|
||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.0" }
|
||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.4.0" }
|
||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.0" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.3.0" }
|
||||
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.3" }
|
||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.5" }
|
||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.2" }
|
||||
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
|
||||
|
||||
[dependencies.tauri]
|
||||
workspace = true
|
||||
@@ -54,17 +55,17 @@ 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.0" }
|
||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.0" }
|
||||
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.9.0" }
|
||||
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.1" }
|
||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.1" }
|
||||
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.3.0" }
|
||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.0" }
|
||||
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.0" }
|
||||
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.0" }
|
||||
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.0" }
|
||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.4" }
|
||||
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" }
|
||||
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.2" }
|
||||
|
||||
[features]
|
||||
prod = ["tauri/custom-protocol"]
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
"core:window:allow-start-dragging",
|
||||
"notification:default",
|
||||
"os:allow-platform",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-ask",
|
||||
"dialog:allow-save",
|
||||
"dialog:allow-confirm",
|
||||
"dialog:allow-message",
|
||||
"dialog:default",
|
||||
{
|
||||
"identifier": "shell:allow-spawn",
|
||||
"allow": [
|
||||
@@ -68,6 +64,9 @@
|
||||
"fs:allow-rename",
|
||||
"fs:allow-mkdir",
|
||||
"fs:allow-remove",
|
||||
"fs:allow-stat",
|
||||
"fs:allow-fstat",
|
||||
"fs:allow-lstat",
|
||||
"fs:allow-write-text-file",
|
||||
"fs:read-meta",
|
||||
"fs:scope-download-recursive",
|
||||
@@ -75,6 +74,9 @@
|
||||
{
|
||||
"identifier": "fs:scope-appdata-recursive",
|
||||
"allow": [
|
||||
{
|
||||
"path": "$APPDATA/db/"
|
||||
},
|
||||
{
|
||||
"path": "$APPDATA/db/**"
|
||||
}
|
||||
@@ -95,6 +97,7 @@
|
||||
{
|
||||
"identifier": "opener:allow-open-path",
|
||||
"allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
|
||||
}
|
||||
},
|
||||
"upload:default"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
namespace = "com.tauri.api"
|
||||
defaultConfig {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
applicationId = "com.tauri.api"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
targetSdk = 36
|
||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:8.5.1")
|
||||
classpath("com.android.tools.build:gradle:8.11.0")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
compileOnly(gradleApi())
|
||||
implementation("com.android.tools.build:gradle:8.5.1")
|
||||
implementation("com.android.tools.build:gradle:8.11.0")
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ pub fn run() {
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_store::Builder::default().build())
|
||||
.plugin(tauri_plugin_upload::init())
|
||||
.setup(move |app| {
|
||||
#[cfg(desktop)]
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import Opener from './views/Opener.svelte'
|
||||
import Store from './views/Store.svelte'
|
||||
import Updater from './views/Updater.svelte'
|
||||
import Upload from './views/Upload.svelte'
|
||||
import Clipboard from './views/Clipboard.svelte'
|
||||
import WebRTC from './views/WebRTC.svelte'
|
||||
import Scanner from './views/Scanner.svelte'
|
||||
@@ -107,6 +108,11 @@
|
||||
component: Updater,
|
||||
icon: 'i-codicon-cloud-download'
|
||||
},
|
||||
{
|
||||
label: 'Upload',
|
||||
component: Upload,
|
||||
icon: 'i-codicon-cloud-upload'
|
||||
},
|
||||
{
|
||||
label: 'Clipboard',
|
||||
component: Clipboard,
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
let filter = null;
|
||||
let multiple = false;
|
||||
let directory = false;
|
||||
let pickerMode = "document";
|
||||
let fileAccessMode = "scoped";
|
||||
|
||||
function arrayBufferToBase64(buffer, callback) {
|
||||
var blob = new Blob([buffer], {
|
||||
@@ -41,58 +43,72 @@
|
||||
}
|
||||
|
||||
async function msg() {
|
||||
await message("Tauri is awesome!");
|
||||
await message("Tauri is awesome!").then((res) => onMessage(res));
|
||||
}
|
||||
|
||||
function openDialog() {
|
||||
open({
|
||||
title: "My wonderful open dialog",
|
||||
defaultPath,
|
||||
filters: filter
|
||||
? [
|
||||
{
|
||||
name: "Tauri Example",
|
||||
extensions: filter.split(",").map((f) => f.trim()),
|
||||
},
|
||||
]
|
||||
: [],
|
||||
multiple,
|
||||
directory,
|
||||
})
|
||||
.then(function (res) {
|
||||
if (Array.isArray(res)) {
|
||||
onMessage(res);
|
||||
} else {
|
||||
var pathToRead = res;
|
||||
var isFile = pathToRead.match(/\S+\.\S+$/g);
|
||||
readFile(pathToRead)
|
||||
.then(function (response) {
|
||||
if (isFile) {
|
||||
if (
|
||||
pathToRead.includes(".png") ||
|
||||
pathToRead.includes(".jpg") ||
|
||||
pathToRead.includes(".jpeg")
|
||||
) {
|
||||
arrayBufferToBase64(
|
||||
new Uint8Array(response),
|
||||
function (base64) {
|
||||
var src = "data:image/png;base64," + base64;
|
||||
insecureRenderHtml('<img src="' + src + '"></img>');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
onMessage(res);
|
||||
}
|
||||
} else {
|
||||
onMessage(res);
|
||||
}
|
||||
})
|
||||
.catch(onMessage(res));
|
||||
}
|
||||
})
|
||||
async function msgCustom(result) {
|
||||
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
|
||||
await message(`Tauri is: `, { buttons })
|
||||
.then((res) => onMessage(`Tauri is ${res}`))
|
||||
.catch(onMessage);
|
||||
}
|
||||
|
||||
async function openDialog() {
|
||||
try {
|
||||
var result = await open({
|
||||
title: "My wonderful open dialog",
|
||||
defaultPath,
|
||||
filters: filter
|
||||
? [
|
||||
{
|
||||
name: "Tauri Example",
|
||||
extensions: filter.split(",").map((f) => f.trim()),
|
||||
},
|
||||
]
|
||||
: [],
|
||||
multiple,
|
||||
directory,
|
||||
pickerMode,
|
||||
fileAccessMode,
|
||||
})
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
onMessage(result);
|
||||
} else {
|
||||
var pathToRead = result;
|
||||
var 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);
|
||||
}
|
||||
} else {
|
||||
onMessage(res);
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch(exception) {
|
||||
onMessage(exception)
|
||||
}
|
||||
}
|
||||
|
||||
function saveDialog() {
|
||||
save({
|
||||
title: "My wonderful save dialog",
|
||||
@@ -105,7 +121,7 @@
|
||||
},
|
||||
]
|
||||
: [],
|
||||
})
|
||||
})
|
||||
.then(onMessage)
|
||||
.catch(onMessage);
|
||||
}
|
||||
@@ -135,13 +151,35 @@
|
||||
<input type="checkbox" id="dialog-directory" bind:checked={directory} />
|
||||
<label for="dialog-directory">Directory</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="dialog-picker-mode">Picker Mode:</label>
|
||||
<select id="dialog-picker-mode" bind:value={pickerMode}>
|
||||
<option value="">None</option>
|
||||
<option value="media">Media</option>
|
||||
<option value="image">Image</option>
|
||||
<option value="video">Video</option>
|
||||
<option value="document">Document</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="dialog-file-access-mode">File Access Mode:</label>
|
||||
<select id="dialog-file-access-mode" bind:value={fileAccessMode}>
|
||||
<option value="copy">Copy</option>
|
||||
<option value="scoped">Scoped</option>
|
||||
</select>
|
||||
</div>
|
||||
<br />
|
||||
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
||||
<button class="btn" id="save-dialog" on:click={saveDialog}
|
||||
>Open save dialog</button
|
||||
>
|
||||
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
|
||||
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
|
||||
>Prompt (custom)</button
|
||||
>
|
||||
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
|
||||
|
||||
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
|
||||
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
||||
<button class="btn" id="save-dialog" on:click={saveDialog}
|
||||
>Open save dialog</button
|
||||
>
|
||||
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
|
||||
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
|
||||
>Prompt (custom)</button
|
||||
>
|
||||
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
|
||||
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,194 +1,214 @@
|
||||
<script>
|
||||
import * as fs from "@tauri-apps/plugin-fs";
|
||||
import { convertFileSrc } from "@tauri-apps/api/core";
|
||||
import { arrayBufferToBase64 } from "../lib/utils";
|
||||
import { onDestroy } from "svelte";
|
||||
import * as fs from '@tauri-apps/plugin-fs'
|
||||
import * as os from '@tauri-apps/plugin-os'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { arrayBufferToBase64 } from '../lib/utils'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
export let onMessage;
|
||||
export let insecureRenderHtml;
|
||||
const { onMessage, insecureRenderHtml } = $props()
|
||||
|
||||
let path = "";
|
||||
let img;
|
||||
let path = $state('')
|
||||
let img
|
||||
/** @type {fs.FileHandle} */
|
||||
let file;
|
||||
let renameTo;
|
||||
let watchPath = "";
|
||||
let watchDebounceDelay = "0";
|
||||
let watchRecursive = false;
|
||||
let unwatchFn;
|
||||
let unwatchPath = "";
|
||||
let file = $state()
|
||||
let renameTo = $state()
|
||||
let watchPath = $state('')
|
||||
let watchDebounceDelay = $state(0)
|
||||
let watchRecursive = $state(false)
|
||||
/** @type {fs.BaseDirectory | undefined} */
|
||||
let baseDir = $state()
|
||||
let unwatchFn
|
||||
let unwatchPath = ''
|
||||
let isMobile = $state(false)
|
||||
|
||||
function getDir() {
|
||||
const dirSelect = document.getElementById("dir");
|
||||
return dirSelect.value ? parseInt(dir.value) : null;
|
||||
}
|
||||
onMount(() => {
|
||||
let platform = os.platform()
|
||||
isMobile = platform === 'android' || platform === 'ios'
|
||||
})
|
||||
|
||||
const DirOptions = Object.keys(fs.BaseDirectory)
|
||||
.filter((key) => isNaN(parseInt(key)))
|
||||
.map((dir) => [dir, fs.BaseDirectory[dir]]);
|
||||
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) =>
|
||||
isNaN(parseInt(key))
|
||||
)
|
||||
|
||||
function open() {
|
||||
fs.open(path, {
|
||||
baseDir: getDir(),
|
||||
baseDir,
|
||||
read: true,
|
||||
write: true,
|
||||
create: true,
|
||||
create: true
|
||||
})
|
||||
.then((f) => {
|
||||
file = f;
|
||||
onMessage(`Opened ${path}`);
|
||||
file = f
|
||||
onMessage(`Opened ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function mkdir() {
|
||||
fs.mkdir(path, { baseDir: getDir() })
|
||||
fs.mkdir(path, { baseDir, recursive: true })
|
||||
.then(() => {
|
||||
onMessage(`Created dir ${path}`);
|
||||
onMessage(`Created dir ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function remove() {
|
||||
fs.remove(path, { baseDir: getDir() })
|
||||
fs.remove(path, { baseDir })
|
||||
.then(() => {
|
||||
onMessage(`Removed ${path}`);
|
||||
onMessage(`Removed ${path}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function rename() {
|
||||
fs.rename(path, renameTo, {
|
||||
oldPathBaseDir: getDir(),
|
||||
newPathBaseDir: getDir(),
|
||||
oldPathBaseDir,
|
||||
newPathBaseDir
|
||||
})
|
||||
.then(() => {
|
||||
onMessage(`Renamed ${path} to ${renameTo}`);
|
||||
onMessage(`Renamed ${path} to ${renameTo}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function truncate() {
|
||||
file
|
||||
.truncate(0)
|
||||
.then(() => {
|
||||
onMessage(`Truncated file`);
|
||||
onMessage(`Truncated file`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function write() {
|
||||
const encoder = new TextEncoder()
|
||||
file
|
||||
.write(encoder.encode('Hello from Tauri :)'))
|
||||
.then(() => {
|
||||
onMessage(`wrote to file`)
|
||||
})
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function stat() {
|
||||
file
|
||||
.stat()
|
||||
.then((stat) => {
|
||||
onMessage(`File stat ${JSON.stringify(stat)}`);
|
||||
onMessage(`File stat ${JSON.stringify(stat)}`)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function read() {
|
||||
const opts = {
|
||||
baseDir: getDir(),
|
||||
};
|
||||
baseDir
|
||||
}
|
||||
fs.stat(path, opts)
|
||||
.then((stat) => {
|
||||
const isFile = stat.isFile;
|
||||
const isFile = stat.isFile
|
||||
|
||||
const promise = isFile
|
||||
? fs.readFile(path, opts)
|
||||
: fs.readDir(path, opts);
|
||||
: fs.readDir(path, opts)
|
||||
promise
|
||||
.then(function (response) {
|
||||
if (isFile) {
|
||||
if (path.includes(".png") || path.includes(".jpg")) {
|
||||
if (path.includes('.png') || path.includes('.jpg')) {
|
||||
arrayBufferToBase64(
|
||||
new Uint8Array(response),
|
||||
function (base64) {
|
||||
const src = "data:image/png;base64," + base64;
|
||||
insecureRenderHtml('<img src="' + src + '"></img>');
|
||||
const src = 'data:image/png;base64,' + base64
|
||||
insecureRenderHtml('<img src="' + src + '"></img>')
|
||||
}
|
||||
);
|
||||
)
|
||||
} else {
|
||||
const value = String.fromCharCode.apply(null, response);
|
||||
const value = String.fromCharCode.apply(null, response)
|
||||
insecureRenderHtml(
|
||||
'<textarea id="file-response"></textarea><button id="file-save">Save</button>'
|
||||
);
|
||||
)
|
||||
setTimeout(() => {
|
||||
const fileInput = document.getElementById("file-response");
|
||||
fileInput.value = value;
|
||||
const fileInput = document.getElementById('file-response')
|
||||
fileInput.value = value
|
||||
document
|
||||
.getElementById("file-save")
|
||||
.addEventListener("click", function () {
|
||||
.getElementById('file-save')
|
||||
.addEventListener('click', function () {
|
||||
fs.writeTextFile(path, fileInput.value, {
|
||||
baseDir: getDir(),
|
||||
}).catch(onMessage);
|
||||
});
|
||||
});
|
||||
baseDir
|
||||
}).catch(onMessage)
|
||||
})
|
||||
})
|
||||
}
|
||||
} else {
|
||||
onMessage(response);
|
||||
onMessage(response)
|
||||
}
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
|
||||
function setSrc() {
|
||||
img.src = convertFileSrc(path);
|
||||
img.src = convertFileSrc(path)
|
||||
}
|
||||
|
||||
function watch() {
|
||||
unwatch();
|
||||
unwatch()
|
||||
if (watchPath) {
|
||||
onMessage(`Watching ${watchPath} for changes`);
|
||||
onMessage(`Watching ${watchPath} for changes`)
|
||||
let options = {
|
||||
recursive: watchRecursive,
|
||||
delayMs: parseInt(watchDebounceDelay),
|
||||
};
|
||||
delayMs: watchDebounceDelay
|
||||
}
|
||||
if (options.delayMs === 0) {
|
||||
fs.watchImmediate(watchPath, onMessage, options)
|
||||
.then((fn) => {
|
||||
unwatchFn = fn;
|
||||
unwatchPath = watchPath;
|
||||
unwatchFn = fn
|
||||
unwatchPath = watchPath
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
} else {
|
||||
fs.watch(watchPath, onMessage, options)
|
||||
.then((fn) => {
|
||||
unwatchFn = fn;
|
||||
unwatchPath = watchPath;
|
||||
unwatchFn = fn
|
||||
unwatchPath = watchPath
|
||||
})
|
||||
.catch(onMessage);
|
||||
.catch(onMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unwatch() {
|
||||
if (unwatchFn) {
|
||||
onMessage(`Stopped watching ${unwatchPath} for changes`);
|
||||
unwatchFn();
|
||||
onMessage(`Stopped watching ${unwatchPath} for changes`)
|
||||
unwatchFn()
|
||||
}
|
||||
unwatchFn = undefined;
|
||||
unwatchPath = undefined;
|
||||
unwatchFn = undefined
|
||||
unwatchPath = undefined
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (file) {
|
||||
file.close();
|
||||
file.close()
|
||||
}
|
||||
if (unwatchFn) {
|
||||
unwatchFn();
|
||||
unwatchFn()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
{#if isMobile}
|
||||
<div>
|
||||
On mobile, paths outside of App* paths require the use of dialogs
|
||||
regardless of Tauri's scope mechanism.
|
||||
</div>
|
||||
<br />
|
||||
{/if}
|
||||
<div class="flex gap-1">
|
||||
<select class="input" id="dir">
|
||||
<option value="">None</option>
|
||||
{#each DirOptions as dir}
|
||||
<option value={dir[1]}>{dir[0]}</option>
|
||||
<select class="input" bind:value={baseDir}>
|
||||
<option value={undefined} selected>None</option>
|
||||
{#each dirOptions as dir}
|
||||
<option value={fs.BaseDirectory[dir]}>{dir}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<input
|
||||
@@ -199,20 +219,21 @@
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn" on:click={open}>Open</button>
|
||||
<button class="btn" on:click={read}>Read</button>
|
||||
<button class="btn" on:click={mkdir}>Mkdir</button>
|
||||
<button class="btn" on:click={remove}>Remove</button>
|
||||
<button class="btn" onclick={open}>Open</button>
|
||||
<button class="btn" onclick={read}>Read</button>
|
||||
<button class="btn" onclick={mkdir}>Mkdir</button>
|
||||
<button class="btn" onclick={remove}>Remove</button>
|
||||
<div class="flex flex-row">
|
||||
<button class="btn" on:click={rename}>Rename</button>
|
||||
<button class="btn" onclick={rename}>Rename</button>
|
||||
<input class="input" bind:value={renameTo} placeholder="To" />
|
||||
</div>
|
||||
<button class="btn" type="button" on:click={setSrc}>Use as img src</button>
|
||||
<button class="btn" type="button" onclick={setSrc}>Use as img src</button>
|
||||
</div>
|
||||
{#if file}
|
||||
<div>
|
||||
<button class="btn" on:click={truncate}>Truncate</button>
|
||||
<button class="btn" on:click={stat}>Stat</button>
|
||||
<button class="btn" onclick={write}>Write</button>
|
||||
<button class="btn" onclick={truncate}>Truncate</button>
|
||||
<button class="btn" onclick={stat}>Stat</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -241,8 +262,8 @@
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button class="btn" on:click={watch}>Watch</button>
|
||||
<button class="btn" on:click={unwatch}>Unwatch</button>
|
||||
<button class="btn" onclick={watch}>Watch</button>
|
||||
<button class="btn" onclick={unwatch}>Unwatch</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<script>
|
||||
import { sendNotification } from '@tauri-apps/plugin-notification'
|
||||
export let onMessage
|
||||
|
||||
let sound = ''
|
||||
|
||||
// send the notification directly
|
||||
// the backend is responsible for checking the permission
|
||||
function _sendNotification() {
|
||||
new Notification('Notification title', {
|
||||
body: 'This is the notification body'
|
||||
sendNotification({
|
||||
title: 'Notification title',
|
||||
body: 'This is the notification body',
|
||||
sound: sound || null
|
||||
})
|
||||
}
|
||||
|
||||
// alternatively, check the permission ourselves
|
||||
function sendNotification() {
|
||||
function triggerNotification() {
|
||||
if (Notification.permission === 'default') {
|
||||
Notification.requestPermission()
|
||||
.then(function (response) {
|
||||
@@ -29,6 +34,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<button class="btn" id="notification" on:click={sendNotification}>
|
||||
<input
|
||||
class="input grow"
|
||||
placeholder="Notification sound..."
|
||||
bind:value={sound}
|
||||
/>
|
||||
<button class="btn" id="notification" on:click={triggerNotification}>
|
||||
Send test notification
|
||||
</button>
|
||||
|
||||
@@ -1,71 +1,85 @@
|
||||
<script>
|
||||
import { LazyStore } from "@tauri-apps/plugin-store";
|
||||
import { onMount } from "svelte";
|
||||
import { appDataDir, resolve } from '@tauri-apps/api/path'
|
||||
import { LazyStore } from '@tauri-apps/plugin-store'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
export let onMessage;
|
||||
let { onMessage } = $props()
|
||||
|
||||
let key;
|
||||
let value;
|
||||
let key = $state()
|
||||
let value = $state()
|
||||
|
||||
let store = new LazyStore("cache.json");
|
||||
let cache = {};
|
||||
const storeName = 'cache.json'
|
||||
|
||||
let store = new LazyStore(storeName)
|
||||
let path = $state('')
|
||||
let cache = $state({})
|
||||
|
||||
async function refreshEntries() {
|
||||
try {
|
||||
const values = await store.entries();
|
||||
cache = {};
|
||||
const values = await store.entries()
|
||||
cache = {}
|
||||
for (const [key, value] of values) {
|
||||
cache[key] = value;
|
||||
cache[key] = value
|
||||
}
|
||||
} catch (error) {
|
||||
onMessage(error);
|
||||
onMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await refreshEntries();
|
||||
});
|
||||
path = await resolve(await appDataDir(), storeName)
|
||||
await refreshEntries()
|
||||
})
|
||||
|
||||
async function write(key, value) {
|
||||
try {
|
||||
if (value) {
|
||||
await store.set(key, value);
|
||||
await store.set(key, value)
|
||||
} else {
|
||||
await store.delete(key);
|
||||
await store.delete(key)
|
||||
}
|
||||
const v = await store.get(key);
|
||||
const v = await store.get(key)
|
||||
if (v === undefined) {
|
||||
delete cache[key];
|
||||
cache = cache;
|
||||
delete cache[key]
|
||||
cache = cache
|
||||
} else {
|
||||
cache[key] = v;
|
||||
cache[key] = v
|
||||
}
|
||||
} catch (error) {
|
||||
onMessage(error);
|
||||
onMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
async function reset() {
|
||||
try {
|
||||
await store.reset();
|
||||
await store.reset()
|
||||
} catch (error) {
|
||||
onMessage(error);
|
||||
onMessage(error)
|
||||
}
|
||||
await refreshEntries();
|
||||
await refreshEntries()
|
||||
}
|
||||
|
||||
async function reload() {
|
||||
try {
|
||||
await store.reload({ overrideDefaults: true })
|
||||
} catch (error) {
|
||||
onMessage(error)
|
||||
}
|
||||
await refreshEntries()
|
||||
}
|
||||
|
||||
async function close() {
|
||||
try {
|
||||
await store.close();
|
||||
onMessage("Store is now closed, any new operations will error out");
|
||||
await store.close()
|
||||
onMessage('Store is now closed, any new operations will error out')
|
||||
} catch (error) {
|
||||
onMessage(error);
|
||||
onMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
function reopen() {
|
||||
store = new LazyStore("cache.json");
|
||||
onMessage("We made a new `LazyStore` instance, operations will now work");
|
||||
store = new LazyStore(storeName)
|
||||
onMessage('We made a new `LazyStore` instance, operations will now work')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -82,14 +96,17 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button class="btn" on:click={() => write(key, value)}>Write</button>
|
||||
<button class="btn" on:click={() => reset()}>Reset</button>
|
||||
<button class="btn" on:click={() => close()}>Close</button>
|
||||
<button class="btn" on:click={() => reopen()}>Re-open</button>
|
||||
<button class="btn" onclick={() => write(key, value)}>Write</button>
|
||||
<button class="btn" onclick={() => reset()}>Reset</button>
|
||||
<button class="btn" onclick={() => reload()}>Reload</button>
|
||||
<button class="btn" onclick={() => close()}>Close</button>
|
||||
<button class="btn" onclick={() => reopen()}>Re-open</button>
|
||||
</div>
|
||||
<div>Store at <code>{path}</code> on disk</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Store Values</h2>
|
||||
{#each Object.entries(cache) as [k, v]}
|
||||
<div>{k} = {v}</div>
|
||||
{/each}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
<script>
|
||||
import { download, upload, HttpMethod } from '@tauri-apps/plugin-upload'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { JsonView } from '@zerodevx/svelte-json-view'
|
||||
import { appDataDir } from '@tauri-apps/api/path'
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
export let onMessage
|
||||
|
||||
let downloadUrl = 'https://httpbin.org/json'
|
||||
let downloadFolder = ''
|
||||
let downloadPath = ''
|
||||
let downloadProgress = null
|
||||
let downloadResult = null
|
||||
let isDownloading = false
|
||||
|
||||
let uploadUrl = 'https://httpbin.org/post'
|
||||
let uploadFilePath = ''
|
||||
let uploadMethod = HttpMethod.Post
|
||||
|
||||
// Update URL when method changes
|
||||
$: {
|
||||
switch (uploadMethod) {
|
||||
case HttpMethod.Post:
|
||||
uploadUrl = 'https://httpbin.org/post'
|
||||
break
|
||||
case HttpMethod.Put:
|
||||
uploadUrl = 'https://httpbin.org/put'
|
||||
break
|
||||
case HttpMethod.Patch:
|
||||
uploadUrl = 'https://httpbin.org/patch'
|
||||
break
|
||||
}
|
||||
}
|
||||
let uploadProgress = null
|
||||
let uploadResult = null
|
||||
let isUploading = false
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
const defaultDir = await appDataDir()
|
||||
if (!downloadFolder) {
|
||||
downloadFolder = defaultDir
|
||||
updateDownloadPath()
|
||||
}
|
||||
} catch (error) {
|
||||
onMessage({ error: `Failed to get default directory: ${error.toString()}` })
|
||||
}
|
||||
})
|
||||
|
||||
async function selectDownloadFolder() {
|
||||
try {
|
||||
const selected = await open({
|
||||
directory: true,
|
||||
multiple: false,
|
||||
defaultPath: downloadFolder || undefined
|
||||
})
|
||||
if (selected) {
|
||||
downloadFolder = selected
|
||||
updateDownloadPath()
|
||||
}
|
||||
} catch (error) {
|
||||
onMessage({ error: error.toString() })
|
||||
}
|
||||
}
|
||||
|
||||
function getFilenameFromUrl(url) {
|
||||
try {
|
||||
const urlObj = new URL(url)
|
||||
let pathname = urlObj.pathname
|
||||
|
||||
// Remove leading slash
|
||||
if (pathname.startsWith('/')) {
|
||||
pathname = pathname.substring(1)
|
||||
}
|
||||
|
||||
// If pathname is empty or ends with slash, use a default name
|
||||
if (!pathname || pathname.endsWith('/')) {
|
||||
return 'downloaded-file.json'
|
||||
}
|
||||
|
||||
// Extract filename from pathname
|
||||
const segments = pathname.split('/')
|
||||
let filename = segments[segments.length - 1]
|
||||
|
||||
// If no extension, try to infer from URL or use default
|
||||
if (!filename.includes('.')) {
|
||||
// Check if URL suggests a file type
|
||||
if (url.includes('json') || urlObj.searchParams.has('format') && urlObj.searchParams.get('format') === 'json') {
|
||||
filename += '.json'
|
||||
} else if (url.includes('xml')) {
|
||||
filename += '.xml'
|
||||
} else if (url.includes('csv')) {
|
||||
filename += '.csv'
|
||||
} else {
|
||||
filename += '.txt'
|
||||
}
|
||||
}
|
||||
|
||||
return filename
|
||||
} catch (error) {
|
||||
return 'downloaded-file.json'
|
||||
}
|
||||
}
|
||||
|
||||
function updateDownloadPath() {
|
||||
if (downloadFolder && downloadUrl) {
|
||||
const filename = getFilenameFromUrl(downloadUrl)
|
||||
downloadPath = `${downloadFolder}/${filename}`
|
||||
} else {
|
||||
downloadPath = ''
|
||||
}
|
||||
}
|
||||
|
||||
// Update download path when URL changes
|
||||
$: if (downloadUrl) {
|
||||
updateDownloadPath()
|
||||
}
|
||||
|
||||
async function selectUploadFile() {
|
||||
try {
|
||||
const selected = await open({
|
||||
directory: false,
|
||||
multiple: false
|
||||
})
|
||||
if (selected) {
|
||||
uploadFilePath = selected
|
||||
}
|
||||
} catch (error) {
|
||||
onMessage({ error: error.toString() })
|
||||
}
|
||||
}
|
||||
|
||||
async function startDownload() {
|
||||
if (!downloadUrl || !downloadFolder) {
|
||||
onMessage({ error: 'Please provide both URL and download folder' })
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure download path is updated
|
||||
updateDownloadPath()
|
||||
|
||||
if (!downloadPath) {
|
||||
onMessage({ error: 'Could not generate download path' })
|
||||
return
|
||||
}
|
||||
|
||||
isDownloading = true
|
||||
downloadProgress = null
|
||||
downloadResult = null
|
||||
|
||||
try {
|
||||
await download(
|
||||
downloadUrl,
|
||||
downloadPath,
|
||||
(progress) => {
|
||||
downloadProgress = {
|
||||
progress: progress.progress,
|
||||
progressTotal: progress.progressTotal,
|
||||
total: progress.total,
|
||||
transferSpeed: progress.transferSpeed,
|
||||
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
||||
}
|
||||
},
|
||||
new Map([
|
||||
['User-Agent', 'Tauri Upload Plugin Demo']
|
||||
])
|
||||
)
|
||||
|
||||
downloadResult = {
|
||||
success: true,
|
||||
message: `File downloaded successfully to: ${downloadPath}`,
|
||||
finalProgress: downloadProgress
|
||||
}
|
||||
|
||||
onMessage({
|
||||
type: 'download',
|
||||
result: downloadResult
|
||||
})
|
||||
} catch (error) {
|
||||
downloadResult = {
|
||||
success: false,
|
||||
error: error.toString()
|
||||
}
|
||||
onMessage({ error: error.toString() })
|
||||
} finally {
|
||||
isDownloading = false
|
||||
}
|
||||
}
|
||||
|
||||
async function startUpload() {
|
||||
if (!uploadUrl || !uploadFilePath) {
|
||||
onMessage({ error: 'Please provide both URL and file path' })
|
||||
return
|
||||
}
|
||||
|
||||
isUploading = true
|
||||
uploadProgress = null
|
||||
uploadResult = null
|
||||
|
||||
try {
|
||||
const response = await upload(
|
||||
uploadUrl,
|
||||
uploadFilePath,
|
||||
(progress) => {
|
||||
uploadProgress = {
|
||||
progress: progress.progress,
|
||||
progressTotal: progress.progressTotal,
|
||||
total: progress.total,
|
||||
transferSpeed: progress.transferSpeed,
|
||||
percentage: progress.total > 0 ? Math.round((progress.progressTotal / progress.total) * 100) : 0
|
||||
}
|
||||
},
|
||||
new Map([
|
||||
['User-Agent', 'Tauri Upload Plugin Demo']
|
||||
]),
|
||||
uploadMethod
|
||||
)
|
||||
|
||||
uploadResult = {
|
||||
success: true,
|
||||
response: response,
|
||||
finalProgress: uploadProgress
|
||||
}
|
||||
|
||||
onMessage({
|
||||
type: 'upload',
|
||||
result: uploadResult
|
||||
})
|
||||
} catch (error) {
|
||||
uploadResult = {
|
||||
success: false,
|
||||
error: error.toString()
|
||||
}
|
||||
onMessage({ error: error.toString() })
|
||||
} finally {
|
||||
isUploading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4 text-gray-800">File Download</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label for="download-url" class="block text-sm font-medium text-gray-700 mb-1">Download URL:</label>
|
||||
<input
|
||||
id="download-url"
|
||||
bind:value={downloadUrl}
|
||||
type="url"
|
||||
placeholder="https://example.com/file.json"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
disabled={isDownloading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="download-folder" class="block text-sm font-medium text-gray-700 mb-1">Download folder:</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
id="download-folder"
|
||||
bind:value={downloadFolder}
|
||||
type="text"
|
||||
placeholder="Select download folder..."
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
disabled={isDownloading}
|
||||
/>
|
||||
<button
|
||||
on:click={selectDownloadFolder}
|
||||
class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600 disabled:opacity-50"
|
||||
disabled={isDownloading}
|
||||
>
|
||||
Browse
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if downloadPath}
|
||||
<div class="bg-blue-50 border border-blue-200 p-3 rounded-md">
|
||||
<div class="text-sm text-blue-800">
|
||||
<strong>File will be saved as:</strong>
|
||||
<div class="font-mono text-xs mt-1 break-all">{downloadPath}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
on:click={startDownload}
|
||||
class="w-full px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
disabled={isDownloading || !downloadUrl || !downloadFolder}
|
||||
>
|
||||
{isDownloading ? 'Downloading...' : 'Download File'}
|
||||
</button>
|
||||
|
||||
{#if downloadProgress}
|
||||
<div class="bg-white p-3 rounded border">
|
||||
<div class="flex justify-between text-sm text-gray-600 mb-1">
|
||||
<span>Progress: {downloadProgress.percentage}%</span>
|
||||
<span>Speed: {Math.round(downloadProgress.transferSpeed / 1024)} KB/s</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
||||
<div
|
||||
class="bg-blue-500 h-2 rounded-full transition-all duration-300"
|
||||
style="width: {downloadProgress.percentage}%"
|
||||
></div>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-1">
|
||||
{Math.round(downloadProgress.progressTotal / 1024)} KB / {Math.round(downloadProgress.total / 1024)} KB
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if downloadResult}
|
||||
<div class="bg-white p-3 rounded border">
|
||||
<JsonView json={downloadResult} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 p-4 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-4 text-gray-800">File Upload</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<label for="upload-url" class="block text-sm font-medium text-gray-700 mb-1">Upload URL:</label>
|
||||
<input
|
||||
id="upload-url"
|
||||
bind:value={uploadUrl}
|
||||
type="url"
|
||||
placeholder="https://httpbin.org/post"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
disabled={isUploading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="upload-file" class="block text-sm font-medium text-gray-700 mb-1">File to upload:</label>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
id="upload-file"
|
||||
bind:value={uploadFilePath}
|
||||
type="text"
|
||||
placeholder="Select file to upload..."
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
disabled={isUploading}
|
||||
/>
|
||||
<button
|
||||
on:click={selectUploadFile}
|
||||
class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600 disabled:opacity-50"
|
||||
disabled={isUploading}
|
||||
>
|
||||
Browse
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="upload-method" class="block text-sm font-medium text-gray-700 mb-1">HTTP Method:</label>
|
||||
<select
|
||||
id="upload-method"
|
||||
bind:value={uploadMethod}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
|
||||
disabled={isUploading}
|
||||
>
|
||||
<option value={HttpMethod.Post}>POST</option>
|
||||
<option value={HttpMethod.Put}>PUT</option>
|
||||
<option value={HttpMethod.Patch}>PATCH</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">Choose the HTTP method for the upload request</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-blue-50 border border-blue-200 p-3 rounded-md">
|
||||
<div class="text-sm text-blue-800">
|
||||
<strong>Upload Configuration:</strong>
|
||||
<div class="font-mono text-xs mt-1">
|
||||
Method: {uploadMethod} | URL: {uploadUrl || 'Not set'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
on:click={startUpload}
|
||||
class="w-full px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
disabled={isUploading || !uploadUrl || !uploadFilePath}
|
||||
>
|
||||
{isUploading ? `Uploading (${uploadMethod})...` : `Upload File (${uploadMethod})`}
|
||||
</button>
|
||||
|
||||
{#if uploadProgress}
|
||||
<div class="bg-white p-3 rounded border">
|
||||
<div class="flex justify-between text-sm text-gray-600 mb-1">
|
||||
<span>Progress: {uploadProgress.percentage}%</span>
|
||||
<span>Speed: {Math.round(uploadProgress.transferSpeed / 1024)} KB/s</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded-full h-2">
|
||||
<div
|
||||
class="bg-green-500 h-2 rounded-full transition-all duration-300"
|
||||
style="width: {uploadProgress.percentage}%"
|
||||
></div>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-1">
|
||||
{Math.round(uploadProgress.progressTotal / 1024)} KB / {Math.round(uploadProgress.total / 1024)} KB
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if uploadResult}
|
||||
<div class="bg-white p-3 rounded border">
|
||||
<JsonView json={uploadResult} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+13
-13
@@ -11,20 +11,20 @@
|
||||
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.29.0",
|
||||
"@rollup/plugin-node-resolve": "16.0.1",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-typescript": "12.1.3",
|
||||
"covector": "^0.12.4",
|
||||
"eslint": "9.29.0",
|
||||
"eslint-config-prettier": "10.1.5",
|
||||
"eslint-plugin-security": "3.0.1",
|
||||
"prettier": "3.6.1",
|
||||
"rollup": "4.44.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@rollup/plugin-node-resolve": "16.0.3",
|
||||
"@rollup/plugin-terser": "1.0.0",
|
||||
"@rollup/plugin-typescript": "12.3.0",
|
||||
"eslint": "10.2.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-plugin-security": "4.0.0",
|
||||
"prettier": "3.8.1",
|
||||
"rollup": "4.59.0",
|
||||
"tslib": "2.8.1",
|
||||
"typescript": "5.8.3",
|
||||
"typescript-eslint": "8.35.0"
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "8.58.2"
|
||||
},
|
||||
"minimumReleaseAge": 4320,
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"esbuild@<0.25.0": ">=0.25.0"
|
||||
@@ -34,6 +34,6 @@
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": "^10.0.0"
|
||||
"pnpm": "^10.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.5.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.
|
||||
|
||||
## \[2.5.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-autostart"
|
||||
version = "2.5.0"
|
||||
version = "2.5.1"
|
||||
description = "Automatically launch your application at startup."
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -9,10 +9,6 @@ rust-version = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
links = "tauri-plugin-autostart"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
windows = { level = "full", notes = "" }
|
||||
linux = { level = "full", notes = "" }
|
||||
|
||||
@@ -33,21 +33,12 @@ tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspac
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-autostart
|
||||
# or
|
||||
npm add @tauri-apps/plugin-autostart
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-autostart
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-autostart#v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-autostart",
|
||||
"version": "2.5.0",
|
||||
"version": "2.5.1",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## \[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.
|
||||
- [`b60dd887`](https://github.com/tauri-apps/plugins-workspace/commit/b60dd88702a2be2af942a3d104d728970a4c42d6) ([#3223](https://github.com/tauri-apps/plugins-workspace/pull/3223)) On iOS, start the scanning session on a separate thread to fix performance issues.
|
||||
- [`c27af912`](https://github.com/tauri-apps/plugins-workspace/commit/c27af9128d6cc7a2424ec49e98005e68b2d0eb1a) ([#3222](https://github.com/tauri-apps/plugins-workspace/pull/3222)) On iOS, fixed an application crash happening when the scanner was started on the iOS Simulator (no camera available).
|
||||
|
||||
## \[2.4.3]
|
||||
|
||||
- [`d8bfe61f`](https://github.com/tauri-apps/plugins-workspace/commit/d8bfe61f20f235314bad93a9c50d8b7f3eade734) ([#3121](https://github.com/tauri-apps/plugins-workspace/pull/3121) by [@NKIPSC](https://github.com/tauri-apps/plugins-workspace/../../NKIPSC)) Remove unnecessary checks on Android when requesting camera permission.
|
||||
- [`631d0e25`](https://github.com/tauri-apps/plugins-workspace/commit/631d0e256a37946b6a9102ca35511abfbebb92c5) ([#2440](https://github.com/tauri-apps/plugins-workspace/pull/2440) by [@kingsword09](https://github.com/tauri-apps/plugins-workspace/../../kingsword09)) Fix the `cameraView` is not removed after scanning in iOS.
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
- [`654bf489`](https://github.com/tauri-apps/plugins-workspace/commit/654bf4891a35769f7e82971641d3ad99974b2dfe) ([#3038](https://github.com/tauri-apps/plugins-workspace/pull/3038) by [@daniel-mader](https://github.com/tauri-apps/plugins-workspace/../../daniel-mader)) Update `androidx.camera` from `1.1.0` to `1.5.1` to support 16 KB memory page sizes.
|
||||
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`aa9140e1`](https://github.com/tauri-apps/plugins-workspace/commit/aa9140e1ac239ab9f015f92b2ed52bbf0eda7c12) ([#2437](https://github.com/tauri-apps/plugins-workspace/pull/2437) by [@enkhjile](https://github.com/tauri-apps/plugins-workspace/../../enkhjile)) Added support for GS1 DataBar on iOS 15.4+
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-barcode-scanner"
|
||||
version = "2.3.0"
|
||||
version = "2.4.4"
|
||||
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -10,8 +10,6 @@ repository = { workspace = true }
|
||||
links = "tauri-plugin-barcode-scanner"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
targets = ["x86_64-linux-android"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
|
||||
@@ -33,21 +33,12 @@ tauri-plugin-barcode-scanner = { git = "https://github.com/tauri-apps/plugins-wo
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-barcode-scanner
|
||||
# or
|
||||
npm add @tauri-apps/plugin-barcode-scanner
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-barcode-scanner
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-barcode-scanner#v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -5,10 +5,10 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "app.tauri.barcodescanner"
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
@@ -33,16 +33,14 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
val camerax_version = "1.5.1"
|
||||
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.camera:camera-core:1.1.0")
|
||||
implementation("androidx.camera:camera-view:1.1.0")
|
||||
implementation("androidx.camera:camera-lifecycle:1.1.0")
|
||||
implementation("androidx.camera:camera-camera2:1.1.0")
|
||||
implementation("androidx.camera:camera-lifecycle:1.1.0")
|
||||
implementation("androidx.camera:camera-view:1.1.0")
|
||||
implementation("androidx.camera:camera-core:${camerax_version}")
|
||||
implementation("androidx.camera:camera-camera2:${camerax_version}")
|
||||
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
|
||||
implementation("androidx.camera:camera-view:${camerax_version}")
|
||||
implementation("com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
|
||||
@@ -54,7 +54,6 @@ import java.util.concurrent.ExecutionException
|
||||
|
||||
private const val PERMISSION_ALIAS_CAMERA = "camera"
|
||||
private const val PERMISSION_NAME = Manifest.permission.CAMERA
|
||||
private const val PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING"
|
||||
|
||||
@InvokeArg
|
||||
class ScanOptions {
|
||||
@@ -354,17 +353,6 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
||||
}
|
||||
}
|
||||
|
||||
private fun markFirstPermissionRequest() {
|
||||
val sharedPreference: SharedPreferences =
|
||||
activity.getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE)
|
||||
sharedPreference.edit().putBoolean(PERMISSION_NAME, false).apply()
|
||||
}
|
||||
|
||||
private fun firstPermissionRequest(): Boolean {
|
||||
return activity.getSharedPreferences(PREFS_PERMISSION_FIRST_TIME_ASKING, MODE_PRIVATE)
|
||||
.getBoolean(PERMISSION_NAME, true)
|
||||
}
|
||||
|
||||
@SuppressLint("ObsoleteSdkInt")
|
||||
@PermissionCallback
|
||||
fun cameraPermissionCallback(invoke: Invoke) {
|
||||
@@ -380,9 +368,7 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (!activity.shouldShowRequestPermissionRationale(PERMISSION_NAME)) {
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
||||
}
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
||||
} else {
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||
}
|
||||
@@ -401,20 +387,12 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (firstPermissionRequest() || activity.shouldShowRequestPermissionRationale(
|
||||
PERMISSION_NAME
|
||||
)
|
||||
) {
|
||||
markFirstPermissionRequest()
|
||||
requestPermissionForAlias(
|
||||
PERMISSION_ALIAS_CAMERA,
|
||||
invoke,
|
||||
"cameraPermissionCallback"
|
||||
)
|
||||
return
|
||||
} else {
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
||||
}
|
||||
requestPermissionForAlias(
|
||||
PERMISSION_ALIAS_CAMERA,
|
||||
invoke,
|
||||
"cameraPermissionCallback"
|
||||
)
|
||||
return
|
||||
} else {
|
||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_BARCODE_SCANNER__=function(n){"use strict";async function e(n,e={},r){return window.__TAURI_INTERNALS__.invoke(n,e,r)}var r;return"function"==typeof SuppressedError&&SuppressedError,n.Format=void 0,(r=n.Format||(n.Format={})).QRCode="QR_CODE",r.UPC_A="UPC_A",r.UPC_E="UPC_E",r.EAN8="EAN_8",r.EAN13="EAN_13",r.Code39="CODE_39",r.Code93="CODE_93",r.Code128="CODE_128",r.Codabar="CODABAR",r.ITF="ITF",r.Aztec="AZTEC",r.DataMatrix="DATA_MATRIX",r.PDF417="PDF_417",n.cancel=async function(){await e("plugin:barcode-scanner|cancel")},n.checkPermissions=async function(){return await async function(n){return e(`plugin:${n}|check_permissions`)}("barcode-scanner").then((n=>n.camera))},n.openAppSettings=async function(){await e("plugin:barcode-scanner|open_app_settings")},n.requestPermissions=async function(){return await async function(n){return e(`plugin:${n}|request_permissions`)}("barcode-scanner").then((n=>n.camera))},n.scan=async function(n){return await e("plugin:barcode-scanner|scan",{...n})},n}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_PLUGIN_BARCODE_SCANNER__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_BARCODE_SCANNER__=function(n){"use strict";async function a(n,a={},e){return window.__TAURI_INTERNALS__.invoke(n,a,e)}var e;return"function"==typeof SuppressedError&&SuppressedError,n.Format=void 0,(e=n.Format||(n.Format={})).QRCode="QR_CODE",e.UPC_A="UPC_A",e.UPC_E="UPC_E",e.EAN8="EAN_8",e.EAN13="EAN_13",e.Code39="CODE_39",e.Code93="CODE_93",e.Code128="CODE_128",e.Codabar="CODABAR",e.ITF="ITF",e.Aztec="AZTEC",e.DataMatrix="DATA_MATRIX",e.PDF417="PDF_417",e.GS1DataBar="GS1_DATA_BAR",e.GS1DataBarLimited="GS1_DATA_BAR_LIMITED",e.GS1DataBarExpanded="GS1_DATA_BAR_EXPANDED",n.cancel=async function(){await a("plugin:barcode-scanner|cancel")},n.checkPermissions=async function(){return await async function(n){return a(`plugin:${n}|check_permissions`)}("barcode-scanner").then(n=>n.camera)},n.openAppSettings=async function(){await a("plugin:barcode-scanner|open_app_settings")},n.requestPermissions=async function(){return await async function(n){return a(`plugin:${n}|request_permissions`)}("barcode-scanner").then(n=>n.camera)},n.scan=async function(n){return await a("plugin:barcode-scanner|scan",{...n})},n}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_PLUGIN_BARCODE_SCANNER__})}
|
||||
|
||||
@@ -12,6 +12,9 @@ export type { PermissionState } from '@tauri-apps/api/core'
|
||||
|
||||
export enum Format {
|
||||
QRCode = 'QR_CODE',
|
||||
/**
|
||||
* Not supported on iOS.
|
||||
*/
|
||||
UPC_A = 'UPC_A',
|
||||
UPC_E = 'UPC_E',
|
||||
EAN8 = 'EAN_8',
|
||||
@@ -19,11 +22,26 @@ export enum Format {
|
||||
Code39 = 'CODE_39',
|
||||
Code93 = 'CODE_93',
|
||||
Code128 = 'CODE_128',
|
||||
/**
|
||||
* Not supported on iOS.
|
||||
*/
|
||||
Codabar = 'CODABAR',
|
||||
ITF = 'ITF',
|
||||
Aztec = 'AZTEC',
|
||||
DataMatrix = 'DATA_MATRIX',
|
||||
PDF417 = 'PDF_417'
|
||||
PDF417 = 'PDF_417',
|
||||
/**
|
||||
* Not supported on Android. Requires iOS 15.4+
|
||||
*/
|
||||
GS1DataBar = 'GS1_DATA_BAR',
|
||||
/**
|
||||
* Not supported on Android. Requires iOS 15.4+
|
||||
*/
|
||||
GS1DataBarLimited = 'GS1_DATA_BAR_LIMITED',
|
||||
/**
|
||||
* Not supported on Android. Requires iOS 15.4+
|
||||
*/
|
||||
GS1DataBarExpanded = 'GS1_DATA_BAR_EXPANDED'
|
||||
}
|
||||
|
||||
export interface ScanOptions {
|
||||
|
||||
@@ -27,8 +27,11 @@ enum SupportedFormat: String, CaseIterable, Decodable {
|
||||
case DATA_MATRIX
|
||||
case PDF_417
|
||||
case QR_CODE
|
||||
case GS1_DATA_BAR
|
||||
case GS1_DATA_BAR_LIMITED
|
||||
case GS1_DATA_BAR_EXPANDED
|
||||
|
||||
var value: AVMetadataObject.ObjectType {
|
||||
var value: AVMetadataObject.ObjectType? {
|
||||
switch self {
|
||||
case .UPC_E: return AVMetadataObject.ObjectType.upce
|
||||
case .EAN_8: return AVMetadataObject.ObjectType.ean8
|
||||
@@ -41,6 +44,24 @@ enum SupportedFormat: String, CaseIterable, Decodable {
|
||||
case .DATA_MATRIX: return AVMetadataObject.ObjectType.dataMatrix
|
||||
case .PDF_417: return AVMetadataObject.ObjectType.pdf417
|
||||
case .QR_CODE: return AVMetadataObject.ObjectType.qr
|
||||
case .GS1_DATA_BAR:
|
||||
if #available(iOS 15.4, *) {
|
||||
return AVMetadataObject.ObjectType.gs1DataBar
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case .GS1_DATA_BAR_LIMITED:
|
||||
if #available(iOS 15.4, *) {
|
||||
return AVMetadataObject.ObjectType.gs1DataBarLimited
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case .GS1_DATA_BAR_EXPANDED:
|
||||
if #available(iOS 15.4, *) {
|
||||
return AVMetadataObject.ObjectType.gs1DataBarExpanded
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,6 +191,7 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
||||
if self.captureSession != nil {
|
||||
self.captureSession!.stopRunning()
|
||||
self.cameraView.removePreviewLayer()
|
||||
self.cameraView.removeFromSuperview()
|
||||
self.captureVideoPreviewLayer = nil
|
||||
self.metaOutput = nil
|
||||
self.captureSession = nil
|
||||
@@ -239,20 +261,34 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
||||
}
|
||||
|
||||
private func runScanner(_ invoke: Invoke, args: ScanOptions) {
|
||||
if getPermissionState() != "granted" {
|
||||
invoke.reject("Camera permission denied or not yet requested")
|
||||
return
|
||||
}
|
||||
|
||||
scanFormats = [AVMetadataObject.ObjectType]()
|
||||
|
||||
(args.formats ?? []).forEach { format in
|
||||
scanFormats.append(format.value)
|
||||
if let formatValue = format.value {
|
||||
scanFormats.append(formatValue)
|
||||
} else {
|
||||
invoke.reject("Unsupported barcode format on this iOS version: \(format)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if scanFormats.count == 0 {
|
||||
if scanFormats.isEmpty {
|
||||
for supportedFormat in SupportedFormat.allCases {
|
||||
scanFormats.append(supportedFormat.value)
|
||||
if let formatValue = supportedFormat.value {
|
||||
scanFormats.append(formatValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.metaOutput!.metadataObjectTypes = self.scanFormats
|
||||
self.captureSession!.startRunning()
|
||||
DispatchQueue.main.async {
|
||||
self.captureSession!.startRunning()
|
||||
}
|
||||
|
||||
self.isScanning = true
|
||||
}
|
||||
@@ -269,6 +305,13 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if camera is available on this platform (iOS simulator doesn't have cameras)
|
||||
let availableVideoDevices = discoverCaptureDevices()
|
||||
if availableVideoDevices.isEmpty {
|
||||
invoke.reject("No camera available on this device (e.g., iOS Simulator)")
|
||||
return
|
||||
}
|
||||
|
||||
var iOS14min: Bool = false
|
||||
if #available(iOS 14.0, *) { iOS14min = true }
|
||||
if !iOS14min && self.getPermissionState() != "granted" {
|
||||
|
||||
@@ -52,6 +52,15 @@ func discoverCaptureDevices() -> [AVCaptureDevice] {
|
||||
}
|
||||
|
||||
func formatStringFromMetadata(_ type: AVMetadataObject.ObjectType) -> String {
|
||||
if #available(iOS 15.4, *) {
|
||||
if type == .gs1DataBar {
|
||||
return "GS1_DATA_BAR"
|
||||
} else if type == .gs1DataBarLimited {
|
||||
return "GS1_DATA_BAR_LIMITED"
|
||||
} else if type == .gs1DataBarExpanded {
|
||||
return "GS1_DATA_BAR_EXPANDED"
|
||||
}
|
||||
}
|
||||
switch type {
|
||||
case AVMetadataObject.ObjectType.upce:
|
||||
return "UPC_E"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-barcode-scanner",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.4",
|
||||
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-biometric"
|
||||
version = "2.3.0"
|
||||
version = "2.3.2"
|
||||
description = "Prompt the user for biometric authentication on Android and iOS."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -9,8 +9,6 @@ repository = { workspace = true }
|
||||
links = "tauri-plugin-biometric"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
targets = ["x86_64-linux-android"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
|
||||
@@ -33,8 +33,6 @@ tauri-plugin-biometric = { git = "https://github.com/tauri-apps/plugins-workspac
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
<!-- Add the branch for installations using git! -->
|
||||
|
||||
```sh
|
||||
@@ -43,13 +41,6 @@ pnpm add @tauri-apps/plugin-biometric
|
||||
npm add @tauri-apps/plugin-biometric
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-biometric
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-biometric#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-biometric#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-biometric#v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -5,10 +5,10 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "app.tauri.biometric"
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-biometric",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.2",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -25,6 +25,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.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.
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-cli"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
description = "Parse arguments from your Tauri application's command line interface."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -9,10 +9,6 @@ rust-version = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
links = "tauri-plugin-cli"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
windows = { level = "full", notes = "" }
|
||||
linux = { level = "full", notes = "" }
|
||||
|
||||
@@ -34,21 +34,12 @@ tauri-plugin-cli = { git = "https://github.com/tauri-apps/plugins-workspace", br
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-cli
|
||||
# or
|
||||
npm add @tauri-apps/plugin-cli
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-cli
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-cli#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-cli#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-cli#v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-cli",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-clipboard-manager"
|
||||
version = "2.3.0"
|
||||
version = "2.3.2"
|
||||
description = "Read and write to the system clipboard."
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
@@ -10,8 +10,7 @@ repository = { workspace = true }
|
||||
links = "tauri-plugin-clipboard-manager"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
|
||||
@@ -33,21 +33,12 @@ tauri-plugin-clipboard-manager = { git = "https://github.com/tauri-apps/plugins-
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-clipboard-manager
|
||||
# or
|
||||
npm add @tauri-apps/plugin-clipboard-manager
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-clipboard-manager
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-clipboard-manager#v2
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -5,10 +5,10 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "app.tauri.clipboard"
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_CLIPBOARD_MANAGER__=function(e){"use strict";var n;async function t(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}"function"==typeof SuppressedError&&SuppressedError;class r{get rid(){return function(e,n,t,r){if("function"==typeof n?e!==n||!r:!n.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?r:"a"===t?r.call(e):r?r.value:n.get(e)}(this,n,"f")}constructor(e){n.set(this,void 0),function(e,n,t){if("function"==typeof n||!n.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");n.set(e,t)}(this,n,e)}async close(){return t("plugin:resources|close",{rid:this.rid})}}n=new WeakMap;class a extends r{constructor(e){super(e)}static async new(e,n,r){return t("plugin:image|new",{rgba:i(e),width:n,height:r}).then((e=>new a(e)))}static async fromBytes(e){return t("plugin:image|from_bytes",{bytes:i(e)}).then((e=>new a(e)))}static async fromPath(e){return t("plugin:image|from_path",{path:e}).then((e=>new a(e)))}async rgba(){return t("plugin:image|rgba",{rid:this.rid}).then((e=>new Uint8Array(e)))}async size(){return t("plugin:image|size",{rid:this.rid})}}function i(e){return null==e?null:"string"==typeof e?e:e instanceof a?e.rid:e}return e.clear=async function(){await t("plugin:clipboard-manager|clear")},e.readImage=async function(){return await t("plugin:clipboard-manager|read_image").then((e=>new a(e)))},e.readText=async function(){return await t("plugin:clipboard-manager|read_text")},e.writeHtml=async function(e,n){await t("plugin:clipboard-manager|write_html",{html:e,altText:n})},e.writeImage=async function(e){await t("plugin:clipboard-manager|write_image",{image:i(e)})},e.writeText=async function(e,n){await t("plugin:clipboard-manager|write_text",{label:n?.label,text:e})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_PLUGIN_CLIPBOARD_MANAGER__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_CLIPBOARD_MANAGER__=function(e){"use strict";var n;async function t(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}"function"==typeof SuppressedError&&SuppressedError;class r{get rid(){return function(e,n,t,r){if("function"==typeof n?e!==n||!r:!n.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?r:"a"===t?r.call(e):r?r.value:n.get(e)}(this,n,"f")}constructor(e){n.set(this,void 0),function(e,n,t){if("function"==typeof n||!n.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");n.set(e,t)}(this,n,e)}async close(){return t("plugin:resources|close",{rid:this.rid})}}n=new WeakMap;class a extends r{constructor(e){super(e)}static async new(e,n,r){return t("plugin:image|new",{rgba:i(e),width:n,height:r}).then(e=>new a(e))}static async fromBytes(e){return t("plugin:image|from_bytes",{bytes:i(e)}).then(e=>new a(e))}static async fromPath(e){return t("plugin:image|from_path",{path:e}).then(e=>new a(e))}async rgba(){return t("plugin:image|rgba",{rid:this.rid}).then(e=>new Uint8Array(e))}async size(){return t("plugin:image|size",{rid:this.rid})}}function i(e){return null==e?null:"string"==typeof e?e:e instanceof a?e.rid:e}return e.clear=async function(){await t("plugin:clipboard-manager|clear")},e.readImage=async function(){return await t("plugin:clipboard-manager|read_image").then(e=>new a(e))},e.readText=async function(){return await t("plugin:clipboard-manager|read_text")},e.writeHtml=async function(e,n){await t("plugin:clipboard-manager|write_html",{html:e,altText:n})},e.writeImage=async function(e){await t("plugin:clipboard-manager|write_image",{image:i(e)})},e.writeText=async function(e,n){await t("plugin:clipboard-manager|write_text",{label:n?.label,text:e})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_PLUGIN_CLIPBOARD_MANAGER__})}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-clipboard-manager",
|
||||
"version": "2.3.0",
|
||||
"version": "2.3.2",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
@@ -24,6 +24,6 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.4.8]
|
||||
|
||||
- [`024ec0c2`](https://github.com/tauri-apps/plugins-workspace/commit/024ec0c29c20cf94579dab9b79d6be0da61a8daa) ([#3214](https://github.com/tauri-apps/plugins-workspace/pull/3214) by [@joshIsCoding](https://github.com/tauri-apps/plugins-workspace/../../joshIsCoding)) Account for differing Android VIEW intent in ChromeOS, fixing deep-link behaviour on Chromium platforms.
|
||||
- [`015e817c`](https://github.com/tauri-apps/plugins-workspace/commit/015e817cf2d7f66c1b9268606af8318dfe0bc4ee) ([#3186](https://github.com/tauri-apps/plugins-workspace/pull/3186) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Validate Android new intent is actually a deep link before triggering the onOpenUrl event.
|
||||
|
||||
## \[2.4.7]
|
||||
|
||||
- [`8374e997`](https://github.com/tauri-apps/plugins-workspace/commit/8374e997b82c95516fc0c1f6d665d9fc3b52edf8) ([#3258](https://github.com/tauri-apps/plugins-workspace/pull/3258) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Fix runtime deep link registration failing on Linux when the app path has spaces.
|
||||
|
||||
## \[2.4.6]
|
||||
|
||||
- [`28048039`](https://github.com/tauri-apps/plugins-workspace/commit/28048039496e84b46847c008416d341f1349e30e) ([#3143](https://github.com/tauri-apps/plugins-workspace/pull/3143) by [@Tunglies](https://github.com/tauri-apps/plugins-workspace/../../Tunglies)) Fix clippy warnings. No user facing changes.
|
||||
|
||||
## \[2.4.5]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
## \[2.4.4]
|
||||
|
||||
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
|
||||
- [`e25a9339`](https://github.com/tauri-apps/plugins-workspace/commit/e25a9339f46268f70dc9afd0c5ab3decbf79b330) ([#3019](https://github.com/tauri-apps/plugins-workspace/pull/3019) by [@kevinschoonover](https://github.com/tauri-apps/plugins-workspace/../../kevinschoonover)) Fix Exec= field in desktop handler if executable path changes
|
||||
|
||||
## \[2.4.3]
|
||||
|
||||
- [`2522b71f`](https://github.com/tauri-apps/plugins-workspace/commit/2522b71f6bcae65c03b24415eb9295c9e7c84ffc) ([#2970](https://github.com/tauri-apps/plugins-workspace/pull/2970) by [@WSH032](https://github.com/tauri-apps/plugins-workspace/../../WSH032)) Revert the breaking change introduced by [#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928).
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
- [`21d721a0`](https://github.com/tauri-apps/plugins-workspace/commit/21d721a0c2731fc201872f5b99ea8bbdc61b0b60) ([#2928](https://github.com/tauri-apps/plugins-workspace/pull/2928) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Linux, improved error messages when OS commands fail.
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
- [`d4f8299b`](https://github.com/tauri-apps/plugins-workspace/commit/d4f8299b12f107718c70692840a63768d65baaf9) ([#2844](https://github.com/tauri-apps/plugins-workspace/pull/2844) by [@yobson1](https://github.com/tauri-apps/plugins-workspace/../../yobson1)) Fix deep link protocol handler not set as default on linux
|
||||
Fix duplicate protocols added to MimeType section in .desktop files on linux
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-deep-link"
|
||||
version = "2.4.0"
|
||||
version = "2.4.8"
|
||||
description = "Set your Tauri application as the default handler for an URL"
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
@@ -10,16 +10,14 @@ repository = { workspace = true }
|
||||
links = "tauri-plugin-deep-link"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustc-args = ["--cfg", "docsrs"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
targets = ["x86_64-linux-android"]
|
||||
|
||||
[package.metadata.platforms.support]
|
||||
windows = { level = "full", notes = "" }
|
||||
linux = { level = "full", notes = "" }
|
||||
macos = { level = "partial", notes = "Runtime deep link registration is not supported" }
|
||||
android = { level = "partial", notes = "Runtime deep link registration is not supported" }
|
||||
ios = { level = "partial", notes = "Runtime deep link registration is not supported" }
|
||||
macos = { level = "partial", notes = "Deep links must be registered in config. Dynamic registration at runtime is not supported." }
|
||||
android = { level = "partial", notes = "Deep links must be registered in config. Dynamic registration at runtime is not supported." }
|
||||
ios = { level = "partial", notes = "Deep links must be registered in config. Dynamic registration at runtime is not supported." }
|
||||
|
||||
[build-dependencies]
|
||||
serde = { workspace = true }
|
||||
@@ -27,6 +25,9 @@ serde_json = { workspace = true }
|
||||
tauri-utils = { workspace = true }
|
||||
tauri-plugin = { workspace = true, features = ["build"] }
|
||||
|
||||
[target."cfg(target_os = \"macos\")".build-dependencies]
|
||||
plist = "1"
|
||||
|
||||
[dependencies]
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -33,21 +33,12 @@ tauri-plugin-deep-link = { git = "https://github.com/tauri-apps/plugins-workspac
|
||||
|
||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||
|
||||
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-deep-link
|
||||
# or
|
||||
npm add @tauri-apps/plugin-deep-link
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-deep-link
|
||||
|
||||
# alternatively with Git:
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-deep-link#v2
|
||||
```
|
||||
|
||||
## Setting up
|
||||
|
||||
@@ -5,10 +5,10 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "app.tauri.deep_link"
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
minSdk = 24
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
|
||||
@@ -6,9 +6,8 @@ package app.tauri.deep_link
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.PatternMatcher
|
||||
import android.webkit.WebView
|
||||
import app.tauri.Logger
|
||||
import app.tauri.annotation.InvokeArg
|
||||
import app.tauri.annotation.Command
|
||||
import app.tauri.annotation.TauriPlugin
|
||||
@@ -16,23 +15,43 @@ import app.tauri.plugin.Channel
|
||||
import app.tauri.plugin.JSObject
|
||||
import app.tauri.plugin.Plugin
|
||||
import app.tauri.plugin.Invoke
|
||||
import androidx.core.net.toUri
|
||||
|
||||
@InvokeArg
|
||||
class SetEventHandlerArgs {
|
||||
lateinit var handler: Channel
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
class AssociatedDomain {
|
||||
var scheme: List<String> = listOf("https", "http")
|
||||
var host: String? = null
|
||||
var path: List<String> = listOf()
|
||||
var pathPattern: List<String> = listOf()
|
||||
var pathPrefix: List<String> = listOf()
|
||||
var pathSuffix: List<String> = listOf()
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
class PluginConfig {
|
||||
var mobile: List<AssociatedDomain> = listOf()
|
||||
}
|
||||
|
||||
@TauriPlugin
|
||||
class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
|
||||
//private val implementation = Example()
|
||||
private var webView: WebView? = null
|
||||
private var currentUrl: String? = null
|
||||
private var channel: Channel? = null
|
||||
|
||||
private var config: PluginConfig? = null
|
||||
companion object {
|
||||
var instance: DeepLinkPlugin? = null
|
||||
}
|
||||
|
||||
private fun isViewIntent(action: String?): Boolean {
|
||||
return action == Intent.ACTION_VIEW || action == "org.chromium.arc.intent.action.VIEW"
|
||||
}
|
||||
|
||||
@Command
|
||||
fun getCurrent(invoke: Invoke) {
|
||||
val ret = JSObject()
|
||||
@@ -51,27 +70,105 @@ class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
|
||||
|
||||
override fun load(webView: WebView) {
|
||||
instance = this
|
||||
|
||||
val intent = activity.intent
|
||||
|
||||
if (intent.action == Intent.ACTION_VIEW) {
|
||||
// TODO: check if it makes sense to split up init url and last url
|
||||
this.currentUrl = intent.data.toString()
|
||||
val event = JSObject()
|
||||
event.put("url", this.currentUrl)
|
||||
this.channel?.send(event)
|
||||
}
|
||||
config = getConfig(PluginConfig::class.java)
|
||||
|
||||
super.load(webView)
|
||||
this.webView = webView
|
||||
|
||||
val intent = activity.intent
|
||||
|
||||
if (isViewIntent(intent.action) && intent.data != null) {
|
||||
val url = intent.data.toString()
|
||||
if (isDeepLink(url)) {
|
||||
// TODO: check if it makes sense to split up init url and last url
|
||||
this.currentUrl = url
|
||||
val event = JSObject()
|
||||
event.put("url", this.currentUrl)
|
||||
this.channel?.send(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_VIEW) {
|
||||
this.currentUrl = intent.data.toString()
|
||||
val event = JSObject()
|
||||
event.put("url", this.currentUrl)
|
||||
this.channel?.send(event)
|
||||
if (isViewIntent(intent.action) && intent.data != null) {
|
||||
val url = intent.data.toString()
|
||||
if (isDeepLink(url)) {
|
||||
this.currentUrl = url
|
||||
val event = JSObject()
|
||||
event.put("url", this.currentUrl)
|
||||
this.channel?.send(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDeepLink(url: String): Boolean {
|
||||
val config = this.config ?: return false
|
||||
|
||||
if (config.mobile.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
val uri = try {
|
||||
url.toUri()
|
||||
} catch (_: Exception) {
|
||||
// not a URL
|
||||
return false
|
||||
}
|
||||
|
||||
val scheme = uri.scheme ?: return false
|
||||
val host = uri.host
|
||||
val path = uri.path ?: ""
|
||||
|
||||
// Check if URL matches any configured mobile deep link
|
||||
for (domain in config.mobile) {
|
||||
// Check scheme
|
||||
if (!domain.scheme.any { it.equals(scheme, ignoreCase = true) }) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check host (if configured)
|
||||
if (domain.host != null) {
|
||||
if (!host.equals(domain.host, ignoreCase = true)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Check path constraints
|
||||
// According to Android docs:
|
||||
// - path: exact match, must begin with /
|
||||
// - pathPrefix: matches initial part of path
|
||||
// - pathSuffix: matches ending part, doesn't need to begin with /
|
||||
// - pathPattern: simple glob pattern (., *, .*)
|
||||
val pathMatches = when {
|
||||
// Exact path match (must begin with /)
|
||||
domain.path.isNotEmpty() && domain.path.any { it == path } -> true
|
||||
// Path pattern match (simple glob: ., *, .*)
|
||||
domain.pathPattern.isNotEmpty() && domain.pathPattern.any { pattern ->
|
||||
try {
|
||||
PatternMatcher(pattern, PatternMatcher.PATTERN_SIMPLE_GLOB).match(path)
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
} -> true
|
||||
// Path prefix match
|
||||
domain.pathPrefix.isNotEmpty() && domain.pathPrefix.any { prefix ->
|
||||
path.startsWith(prefix)
|
||||
} -> true
|
||||
// Path suffix match
|
||||
domain.pathSuffix.isNotEmpty() && domain.pathSuffix.any { suffix ->
|
||||
path.endsWith(suffix)
|
||||
} -> true
|
||||
// If no path constraints, any path is allowed
|
||||
domain.path.isEmpty() && domain.pathPattern.isEmpty() &&
|
||||
domain.pathPrefix.isEmpty() && domain.pathSuffix.isEmpty() -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (pathMatches) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_DEEP_LINK__=function(e){"use strict";function n(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}async function r(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}var t;async function i(e,t,i){const _={kind:"Any"};return r("plugin:event|listen",{event:e,target:_,handler:n(t)}).then((n=>async()=>async function(e,n){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(e,n),await r("plugin:event|unlisten",{event:e,eventId:n})}(e,n)))}return"function"==typeof SuppressedError&&SuppressedError,function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"}(t||(t={})),e.getCurrent=async function(){return await r("plugin:deep-link|get_current")},e.isRegistered=async function(e){return await r("plugin:deep-link|is_registered",{protocol:e})},e.onOpenUrl=async function(e){return await i("deep-link://new-url",(n=>{e(n.payload)}))},e.register=async function(e){return await r("plugin:deep-link|register",{protocol:e})},e.unregister=async function(e){return await r("plugin:deep-link|unregister",{protocol:e})},e}({});Object.defineProperty(window.__TAURI__,"deepLink",{value:__TAURI_PLUGIN_DEEP_LINK__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_DEEP_LINK__=function(e){"use strict";function n(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}async function r(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}var t;async function i(e,t,i){const _={kind:"Any"};return r("plugin:event|listen",{event:e,target:_,handler:n(t)}).then(n=>async()=>async function(e,n){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(e,n),await r("plugin:event|unlisten",{event:e,eventId:n})}(e,n))}return"function"==typeof SuppressedError&&SuppressedError,function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WINDOW_SUSPENDED="tauri://suspended",e.WINDOW_RESUMED="tauri://resumed",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"}(t||(t={})),e.getCurrent=async function(){return await r("plugin:deep-link|get_current")},e.isRegistered=async function(e){return await r("plugin:deep-link|is_registered",{protocol:e})},e.onOpenUrl=async function(e){return await i("deep-link://new-url",n=>{e(n.payload)})},e.register=async function(e){return await r("plugin:deep-link|register",{protocol:e})},e.unregister=async function(e){return await r("plugin:deep-link|unregister",{protocol:e})},e}({});Object.defineProperty(window.__TAURI__,"deepLink",{value:__TAURI_PLUGIN_DEEP_LINK__})}
|
||||
|
||||
+115
-26
@@ -10,50 +10,66 @@ const COMMANDS: &[&str] = &["get_current", "register", "unregister", "is_registe
|
||||
|
||||
// TODO: Consider using activity-alias in case users may have multiple activities in their app.
|
||||
fn intent_filter(domain: &AssociatedDomain) -> String {
|
||||
let host = domain
|
||||
.host
|
||||
.as_ref()
|
||||
.map(|h| format!(r#"<data android:host="{h}" />"#))
|
||||
.unwrap_or_default();
|
||||
|
||||
let auto_verify = if domain.is_app_link() {
|
||||
r#"android:autoVerify="true" "#.to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"<intent-filter android:autoVerify="true">
|
||||
r#"<intent-filter {auto_verify}>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<!-- ChromeOS ARC++ uses a different action for deep links -->
|
||||
<action android:name="org.chromium.arc.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
{}
|
||||
<data android:host="{}" />
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{}
|
||||
{schemes}
|
||||
{host}
|
||||
{domains}
|
||||
{path_patterns}
|
||||
{path_prefixes}
|
||||
{path_suffixes}
|
||||
</intent-filter>"#,
|
||||
domain
|
||||
schemes = domain
|
||||
.scheme
|
||||
.iter()
|
||||
.map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain.host,
|
||||
domain
|
||||
host = host,
|
||||
domains = domain
|
||||
.path
|
||||
.iter()
|
||||
.map(|path| format!(r#"<data android:path="{path}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_patterns = domain
|
||||
.path_pattern
|
||||
.iter()
|
||||
.map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_prefixes = domain
|
||||
.path_prefix
|
||||
.iter()
|
||||
.map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
domain
|
||||
path_suffixes = domain
|
||||
.path_suffix
|
||||
.iter()
|
||||
.map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n "),
|
||||
)
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -68,6 +84,16 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(config) = tauri_plugin::plugin_config::<Config>("deep-link") {
|
||||
let errors: Vec<String> = config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter_map(|d| d.validate().err())
|
||||
.collect();
|
||||
|
||||
if !errors.is_empty() {
|
||||
panic!("Deep link config validation failed:\n{}", errors.join("\n"));
|
||||
}
|
||||
|
||||
tauri_plugin::mobile::update_android_manifest(
|
||||
"DEEP LINK PLUGIN",
|
||||
"activity",
|
||||
@@ -80,20 +106,83 @@ fn main() {
|
||||
)
|
||||
.expect("failed to rewrite AndroidManifest.xml");
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
{
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.insert(
|
||||
"com.apple.developer.associated-domains".into(),
|
||||
config
|
||||
.mobile
|
||||
.into_iter()
|
||||
.map(|d| format!("applinks:{}", d.host).into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
// we need to ensure that the entitlements are only
|
||||
// generated for explicit app links and not
|
||||
// other deep links because then they
|
||||
// are just going to complain and not be built or signed
|
||||
let has_app_links = config.mobile.iter().any(|d| d.is_app_link());
|
||||
|
||||
if !has_app_links {
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.remove("com.apple.developer.associated-domains");
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
} else {
|
||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||
entitlements.insert(
|
||||
"com.apple.developer.associated-domains".into(),
|
||||
config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter(|d| d.is_app_link())
|
||||
.filter_map(|d| d.host.as_ref())
|
||||
.map(|host| format!("applinks:{}", host).into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update entitlements");
|
||||
}
|
||||
|
||||
let deep_link_domains = config
|
||||
.mobile
|
||||
.iter()
|
||||
.filter(|domain| !domain.is_app_link())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if deep_link_domains.is_empty() {
|
||||
tauri_plugin::mobile::update_info_plist(|info_plist| {
|
||||
info_plist.remove("CFBundleURLTypes");
|
||||
})
|
||||
.expect("failed to update Info.plist");
|
||||
} else {
|
||||
tauri_plugin::mobile::update_info_plist(|info_plist| {
|
||||
info_plist.insert(
|
||||
"CFBundleURLTypes".into(),
|
||||
deep_link_domains
|
||||
.iter()
|
||||
.map(|domain| {
|
||||
let schemes = domain
|
||||
.scheme
|
||||
.iter()
|
||||
.filter(|scheme| {
|
||||
scheme.as_str() != "https" && scheme.as_str() != "http"
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut dict = plist::Dictionary::new();
|
||||
dict.insert(
|
||||
"CFBundleURLSchemes".into(),
|
||||
schemes
|
||||
.iter()
|
||||
.map(|s| s.to_string().into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
dict.insert(
|
||||
"CFBundleURLName".into(),
|
||||
domain.scheme[0].clone().into(),
|
||||
);
|
||||
plist::Value::Dictionary(dict)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
.expect("failed to update Info.plist");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.2.11]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.8`
|
||||
|
||||
## \[2.2.10]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.7`
|
||||
|
||||
## \[2.2.9]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.6`
|
||||
|
||||
## \[2.2.8]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.5`
|
||||
|
||||
## \[2.2.7]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.4`
|
||||
|
||||
## \[2.2.6]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.3`
|
||||
|
||||
## \[2.2.5]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.2`
|
||||
|
||||
## \[2.2.4]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `deep-link-js@2.4.1`
|
||||
|
||||
## \[2.2.3]
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deep-link-example",
|
||||
"private": true,
|
||||
"version": "2.2.3",
|
||||
"version": "2.2.11",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -10,12 +10,12 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.6.0",
|
||||
"@tauri-apps/plugin-deep-link": "2.4.0"
|
||||
"@tauri-apps/api": "^2.11.0",
|
||||
"@tauri-apps/plugin-deep-link": "2.4.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.6.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.2.6"
|
||||
"@tauri-apps/cli": "2.11.0",
|
||||
"typescript": "^6.0.0",
|
||||
"vite": "^8.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 34
|
||||
compileSdk = 36
|
||||
namespace = "com.tauri.deep_link_example"
|
||||
defaultConfig {
|
||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||
applicationId = "com.tauri.deep_link_example"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
targetSdk = 36
|
||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||
}
|
||||
@@ -58,9 +58,10 @@ rust {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("androidx.webkit:webkit:1.6.1")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.8.0")
|
||||
implementation("androidx.webkit:webkit:1.14.0")
|
||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||
|
||||
+21
-4
@@ -23,23 +23,40 @@
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<intent-filter android:autoVerify="true" >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="http" />
|
||||
<data android:host="fabianlars.de" />
|
||||
|
||||
|
||||
<data android:pathPrefix="/intent" />
|
||||
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<intent-filter android:autoVerify="true" >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:scheme="http" />
|
||||
<data android:host="tauri.app" />
|
||||
|
||||
|
||||
|
||||
|
||||
</intent-filter>
|
||||
<intent-filter >
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="taurideeplink" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</intent-filter>
|
||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||
</activity>
|
||||
|
||||
+9
-5
@@ -1,7 +1,11 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package com.tauri.deep_link_example
|
||||
|
||||
class MainActivity : TauriActivity()
|
||||
import android.os.Bundle
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
|
||||
class MainActivity : TauriActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
enableEdgeToEdge()
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:8.5.1")
|
||||
classpath("com.android.tools.build:gradle:8.11.0")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,6 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
compileOnly(gradleApi())
|
||||
implementation("com.android.tools.build:gradle:8.5.1")
|
||||
implementation("com.android.tools.build:gradle:8.11.0")
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Tue May 10 19:22:52 CST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
+77
-77
@@ -1,116 +1,116 @@
|
||||
{
|
||||
"images": [
|
||||
"images" : [
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-20x20@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-20x20@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-29x29@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-29x29@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-40x40@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-40x40@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-60x60@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "60x60",
|
||||
"idiom": "iphone",
|
||||
"filename": "AppIcon-60x60@3x.png",
|
||||
"scale": "3x"
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-20x20@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "20x20",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-20x20@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-29x29@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "29x29",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-29x29@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-40x40@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "40x40",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-40x40@2x-1.png",
|
||||
"scale": "2x"
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-76x76@1x.png",
|
||||
"scale": "1x"
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size": "76x76",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-76x76@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "83.5x83.5",
|
||||
"idiom": "ipad",
|
||||
"filename": "AppIcon-83.5x83.5@2x.png",
|
||||
"scale": "2x"
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size": "1024x1024",
|
||||
"idiom": "ios-marketing",
|
||||
"filename": "AppIcon-512@2x.png",
|
||||
"scale": "1x"
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17150" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
|
||||
+12
-34
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objectVersion = 63;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -167,6 +167,8 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = "deep-link-example_iOS";
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = "deep-link-example_iOS";
|
||||
productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@@ -189,6 +191,7 @@
|
||||
en,
|
||||
);
|
||||
mainGroup = 1DC58B1705AA3ECC6B887FE7;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
@@ -227,7 +230,6 @@
|
||||
outputPaths = (
|
||||
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
|
||||
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
|
||||
"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
@@ -314,18 +316,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = (
|
||||
arm64,
|
||||
"arm64-sim",
|
||||
);
|
||||
ARCHS = arm64;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\".\"",
|
||||
@@ -335,13 +332,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||
@@ -360,7 +350,7 @@
|
||||
PRODUCT_NAME = "deep-link-example";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = "arm64 arm64-sim";
|
||||
VALID_ARCHS = arm64;
|
||||
};
|
||||
name = debug;
|
||||
};
|
||||
@@ -424,18 +414,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ARCHS = (
|
||||
arm64,
|
||||
"arm64-sim",
|
||||
);
|
||||
ARCHS = arm64;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\".\"",
|
||||
@@ -445,13 +430,6 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
|
||||
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
|
||||
);
|
||||
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||
@@ -470,7 +448,7 @@
|
||||
PRODUCT_NAME = "deep-link-example";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = "arm64 arm64-sim";
|
||||
VALID_ARCHS = arm64;
|
||||
};
|
||||
name = release;
|
||||
};
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+12
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.0</string>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
@@ -40,5 +40,16 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>taurideeplink</string>
|
||||
</array>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>taurideeplink</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,7 +1,3 @@
|
||||
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: deep-link-example
|
||||
options:
|
||||
bundleIdPrefix: com.tauri.deep-link-example
|
||||
@@ -16,7 +12,6 @@ settingGroups:
|
||||
base:
|
||||
PRODUCT_NAME: deep-link-example
|
||||
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example
|
||||
DEVELOPMENT_TEAM: Q93MBH6S2F
|
||||
targetTemplates:
|
||||
app:
|
||||
type: application
|
||||
@@ -56,8 +51,8 @@ targets:
|
||||
- UIInterfaceOrientationPortraitUpsideDown
|
||||
- UIInterfaceOrientationLandscapeLeft
|
||||
- UIInterfaceOrientationLandscapeRight
|
||||
CFBundleShortVersionString: 0.0.0
|
||||
CFBundleVersion: 0.0.0
|
||||
CFBundleShortVersionString: 0.1.0
|
||||
CFBundleVersion: '0.1.0'
|
||||
entitlements:
|
||||
path: deep-link-example_iOS/deep-link-example_iOS.entitlements
|
||||
scheme:
|
||||
@@ -67,14 +62,12 @@ targets:
|
||||
settings:
|
||||
base:
|
||||
ENABLE_BITCODE: false
|
||||
ARCHS: [arm64, arm64-sim]
|
||||
VALID_ARCHS: arm64 arm64-sim
|
||||
ARCHS: [arm64]
|
||||
VALID_ARCHS: arm64
|
||||
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
|
||||
EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
|
||||
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
||||
groups: [app]
|
||||
dependencies:
|
||||
- framework: libapp.a
|
||||
@@ -93,4 +86,3 @@ targets:
|
||||
outputFiles:
|
||||
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
|
||||
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
|
||||
- $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
},
|
||||
{
|
||||
"host": "tauri.app"
|
||||
},
|
||||
{
|
||||
"scheme": ["taurideeplink"]
|
||||
}
|
||||
],
|
||||
"desktop": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-deep-link",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.8",
|
||||
"description": "Set your Tauri application as the default handler for an URL",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
@@ -25,6 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.6.0"
|
||||
"@tauri-apps/api": "^2.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@ use tauri_utils::config::DeepLinkProtocol;
|
||||
pub struct AssociatedDomain {
|
||||
#[serde(default = "default_schemes")]
|
||||
pub scheme: Vec<String>,
|
||||
|
||||
#[serde(deserialize_with = "deserialize_associated_host")]
|
||||
pub host: String,
|
||||
|
||||
#[serde(default, deserialize_with = "deserialize_associated_host")]
|
||||
pub host: Option<String>, // Optional custom uri schemes dont NEED a host (may have one still), but required for https/http schemes
|
||||
#[serde(default)]
|
||||
pub path: Vec<String>,
|
||||
#[serde(default, alias = "path-pattern", rename = "pathPattern")]
|
||||
@@ -23,6 +21,41 @@ pub struct AssociatedDomain {
|
||||
pub path_prefix: Vec<String>,
|
||||
#[serde(default, alias = "path-suffix", rename = "pathSuffix")]
|
||||
pub path_suffix: Vec<String>,
|
||||
#[serde(default, alias = "app-link", rename = "appLink")]
|
||||
pub app_link: Option<bool>,
|
||||
}
|
||||
|
||||
impl AssociatedDomain {
|
||||
/// Returns true if the domain uses http or https scheme.
|
||||
pub fn is_web_link(&self) -> bool {
|
||||
self.scheme.iter().any(|s| s == "https" || s == "http")
|
||||
}
|
||||
|
||||
/// Returns true if the domain uses http or https scheme and has proper host configuration.
|
||||
pub fn is_app_link(&self) -> bool {
|
||||
self.app_link
|
||||
.unwrap_or_else(|| self.is_web_link() && self.host.is_some())
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
// Rule 1: All web links require a host.
|
||||
if self.is_web_link() && self.host.is_none() {
|
||||
return Err("Web link requires a host".into());
|
||||
}
|
||||
|
||||
// Rule 2: If it's an App Link, ensure http(s) and host.
|
||||
if self.is_app_link() {
|
||||
if !self.is_web_link() {
|
||||
return Err("AppLink must be a valid web link (https/http + host)".into());
|
||||
}
|
||||
if self.scheme.iter().any(|s| s == "http") && !self.scheme.iter().any(|s| s == "https")
|
||||
{
|
||||
eprintln!("Warning: AppLink uses only 'http' — allowed on Android but not secure for production.");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Consider removing this in v3
|
||||
@@ -30,18 +63,19 @@ fn default_schemes() -> Vec<String> {
|
||||
vec!["https".to_string(), "http".to_string()]
|
||||
}
|
||||
|
||||
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let host = String::deserialize(deserializer)?;
|
||||
if let Some((scheme, _host)) = host.split_once("://") {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||
)))
|
||||
} else {
|
||||
Ok(host)
|
||||
let opt = Option::<String>::deserialize(deserializer)?;
|
||||
if let Some(ref host) = opt {
|
||||
if let Some((scheme, _)) = host.split_once("://") {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(opt)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
|
||||
@@ -28,6 +28,16 @@ pub enum Error {
|
||||
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
|
||||
}
|
||||
|
||||
// TODO(v3): change this into an error in v3,
|
||||
// see <https://github.com/tauri-apps/plugins-workspace/pull/2970#issuecomment-3244660138>.
|
||||
#[inline]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) fn inspect_command_error<'a>(command: &'a str) -> impl Fn(&std::io::Error) + 'a {
|
||||
move |e| {
|
||||
tracing::error!("Failed to run OS command `{command}`: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
|
||||
@@ -254,6 +254,7 @@ mod imp {
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Linux**: Needs the `xdg-mime` and `update-desktop-database` commands available on the system.
|
||||
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||
pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> {
|
||||
#[cfg(windows)]
|
||||
@@ -292,6 +293,7 @@ mod imp {
|
||||
.unwrap_or_else(|| bin.into_os_string())
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let qualified_exec = format!("\"{}\" %u", exec);
|
||||
|
||||
let target = self.app.path().data_dir()?.join("applications");
|
||||
|
||||
@@ -303,12 +305,30 @@ mod imp {
|
||||
|
||||
if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) {
|
||||
if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) {
|
||||
let old_mimes = section.remove("MimeType");
|
||||
section.append(
|
||||
"MimeType",
|
||||
format!("{mime_type};{}", old_mimes.unwrap_or_default()),
|
||||
);
|
||||
desktop_file.write_to_file(&target_file)?;
|
||||
let old_mimes = section.remove("MimeType").unwrap_or_default();
|
||||
let mut change = false;
|
||||
|
||||
// if the mime type is not present, append it to the list
|
||||
if !old_mimes.split(';').any(|mime| mime == mime_type) {
|
||||
section.append("MimeType", format!("{mime_type};{old_mimes}"));
|
||||
change = true;
|
||||
} else {
|
||||
section.insert("MimeType".to_string(), old_mimes);
|
||||
}
|
||||
|
||||
// if the exec command doesnt match, update to the new one
|
||||
let old_exec = section.remove("Exec").unwrap_or_default();
|
||||
if old_exec != qualified_exec {
|
||||
section.append("Exec", qualified_exec);
|
||||
change = true;
|
||||
} else {
|
||||
section.insert("Exec".to_string(), old_exec.to_string());
|
||||
}
|
||||
|
||||
// if any property has changed, rewrite the .desktop file
|
||||
if change {
|
||||
desktop_file.write_to_file(&target_file)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut file = File::create(target_file)?;
|
||||
@@ -321,7 +341,7 @@ mod imp {
|
||||
.product_name
|
||||
.clone()
|
||||
.unwrap_or_else(|| file_name.clone()),
|
||||
exec = exec,
|
||||
qualified_exec = qualified_exec,
|
||||
mime_type = mime_type
|
||||
)
|
||||
.as_bytes(),
|
||||
@@ -330,11 +350,15 @@ mod imp {
|
||||
|
||||
Command::new("update-desktop-database")
|
||||
.arg(target)
|
||||
.status()?;
|
||||
.status()
|
||||
.inspect_err(crate::error::inspect_command_error(
|
||||
"update-desktop-database",
|
||||
))?;
|
||||
|
||||
Command::new("xdg-mime")
|
||||
.args(["default", &file_name, _protocol.as_ref()])
|
||||
.status()?;
|
||||
.args(["default", &file_name, mime_type.as_str()])
|
||||
.status()
|
||||
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -403,6 +427,7 @@ mod imp {
|
||||
///
|
||||
/// ## Platform-specific:
|
||||
///
|
||||
/// - **Linux**: Needs the `xdg-mime` command available on the system.
|
||||
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||
pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> {
|
||||
#[cfg(windows)]
|
||||
@@ -437,7 +462,8 @@ mod imp {
|
||||
"default",
|
||||
&format!("x-scheme-handler/{}", _protocol.as_ref()),
|
||||
])
|
||||
.output()?;
|
||||
.output()
|
||||
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&output.stdout).contains(&file_name))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name={name}
|
||||
Exec={exec} %u
|
||||
Exec={qualified_exec}
|
||||
Terminal=false
|
||||
MimeType={mime_type}
|
||||
NoDisplay=true
|
||||
NoDisplay=true
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "guest-js"
|
||||
},
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# Changelog
|
||||
|
||||
## \[2.7.0]
|
||||
|
||||
- [`24154472`](https://github.com/tauri-apps/plugins-workspace/commit/24154472a6710a690173df0a121125d1f1b871e8) ([#3287](https://github.com/tauri-apps/plugins-workspace/pull/3287) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Re-use `message` command in Rust side for `ask` and `confirm` commands, `allow-ask` and `allow-confirm` permissions are now aliases to `allow-message`
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.5.0`
|
||||
|
||||
## \[2.6.0]
|
||||
|
||||
- [`d7a0bb32`](https://github.com/tauri-apps/plugins-workspace/commit/d7a0bb325dad919d6cc132eb3898c33540de77c4) ([#3136](https://github.com/tauri-apps/plugins-workspace/pull/3136) by [@onehumandev](https://github.com/tauri-apps/plugins-workspace/../../onehumandev)) Add `fileAccessMode` option to file picker.
|
||||
|
||||
## \[2.5.0]
|
||||
|
||||
- [`dff6fa98`](https://github.com/tauri-apps/plugins-workspace/commit/dff6fa986a9a05ba98b6ca660fea78ae97251fc2) ([#3034](https://github.com/tauri-apps/plugins-workspace/pull/3034) by [@onehumandev](https://github.com/tauri-apps/plugins-workspace/../../onehumandev)) Add `pickerMode` option to file picker (currently only used on iOS)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.5`
|
||||
|
||||
### feat
|
||||
|
||||
- [`c23fa03f`](https://github.com/tauri-apps/plugins-workspace/commit/c23fa03f07d5c1c220bcf0bca482364513e3f754) ([#3098](https://github.com/tauri-apps/plugins-workspace/pull/3098) by [@Lepidopteran](https://github.com/tauri-apps/plugins-workspace/../../Lepidopteran)) Add `xdg-portal` as an optional feature for `rfd`
|
||||
|
||||
## \[2.4.2]
|
||||
|
||||
- [`93426f85`](https://github.com/tauri-apps/plugins-workspace/commit/93426f85120f49beb9f40222bff45185a32d54a9) Fixed an issue that caused docs.rs builds to fail. No user facing changes.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.4`
|
||||
|
||||
## \[2.4.1]
|
||||
|
||||
- [`6c9b61fb`](https://github.com/tauri-apps/plugins-workspace/commit/6c9b61fb658145d13893626112fc489f7458aa17) ([#3039](https://github.com/tauri-apps/plugins-workspace/pull/3039) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) On Android, updated compileSdk to 36.
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.3`
|
||||
|
||||
## \[2.4.0]
|
||||
|
||||
- [`509eba8d`](https://github.com/tauri-apps/plugins-workspace/commit/509eba8d441c4f6ecf0af77b572cb2afd69a752d) ([#2641](https://github.com/tauri-apps/plugins-workspace/pull/2641) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Add support for showing a message dialog with 3 buttons.
|
||||
|
||||
## \[2.3.3]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.2`
|
||||
|
||||
## \[2.3.2]
|
||||
|
||||
- [`af08c66f`](https://github.com/tauri-apps/plugins-workspace/commit/af08c66faafe0dffc4b0a80aef030cd3f0f89a9c) ([#2871](https://github.com/tauri-apps/plugins-workspace/pull/2871) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused the file picker not to open on Android when extension filters were set.
|
||||
|
||||
## \[2.3.1]
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Upgraded to `fs-js@2.4.1`
|
||||
|
||||
## \[2.3.0]
|
||||
|
||||
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user