mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-18 14:40:07 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15fc071773 | |||
| 73c6047b78 |
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fs: patch
|
||||||
|
fs-js: patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixed calling `writeFile` with `data: ReadableStream` throws `Invalid argument`
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
nfc: patch
|
||||||
|
nfc-js: patch
|
||||||
|
---
|
||||||
|
|
||||||
|
On iOS, the reader session will now get closed properly on errors, preventing dangling invalid sessions that could prevent subsequent write attempts.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"opener": 'minor:enhance'
|
||||||
|
"opener-js": 'minor:enhance'
|
||||||
|
---
|
||||||
|
|
||||||
|
Allow reveal multiple items in the file explorer.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
store: minor
|
||||||
|
store-js: minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Allow setting defaults from the JavaScript API
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
store: minor
|
||||||
|
store-js: minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add an new option `overrideDefaults` for creating/loading and reloading the store that overrides the store with the on-disk state, ignoring defaults
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
name: 📚 Docs Report
|
|
||||||
about: Create a report to help us improve the docs
|
|
||||||
labels: 'type: documentation'
|
|
||||||
---
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -11,7 +11,7 @@ on:
|
|||||||
- v2
|
- v2
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
# required for oidc token
|
# required for npm provenance
|
||||||
id-token: write
|
id-token: write
|
||||||
# required to create the GitHub Release
|
# required to create the GitHub Release
|
||||||
contents: write
|
contents: write
|
||||||
@@ -62,6 +62,7 @@ jobs:
|
|||||||
id: covector
|
id: covector
|
||||||
env:
|
env:
|
||||||
CARGO_TARGET_DIR: /mnt/target
|
CARGO_TARGET_DIR: /mnt/target
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
command: 'version-or-publish'
|
command: 'version-or-publish'
|
||||||
|
|||||||
@@ -154,5 +154,4 @@ jobs:
|
|||||||
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
|
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
|
||||||
|
|
||||||
- name: clippy ${{ matrix.package }} --all-features
|
- name: clippy ${{ matrix.package }} --all-features
|
||||||
if: matrix.package != 'tauri-plugin-dialog'
|
|
||||||
run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
|
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
|
run: cargo +stable install cross --git https://github.com/cross-rs/cross
|
||||||
|
|
||||||
- name: test ${{ matrix.package }}
|
- name: test ${{ matrix.package }}
|
||||||
if: ${{ matrix.package != 'tauri-plugin-http' && matrix.package != 'tauri-plugin-dialog' }}
|
if: matrix.package != 'tauri-plugin-http'
|
||||||
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
|
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
|
||||||
|
|
||||||
- name: test ${{ matrix.package }}
|
- name: test ${{ matrix.package }}
|
||||||
if: ${{ matrix.package == 'tauri-plugin-http' || matrix.package == 'tauri-plugin-dialog' }}
|
if: matrix.package == 'tauri-plugin-http'
|
||||||
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
|
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
|
||||||
|
|||||||
+1
-1
@@ -58,4 +58,4 @@ pids
|
|||||||
.idea
|
.idea
|
||||||
debug.log
|
debug.log
|
||||||
TODO.md
|
TODO.md
|
||||||
.aider.*
|
.aider*
|
||||||
|
|||||||
Generated
+137
-240
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -12,10 +12,10 @@ resolver = "2"
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
tauri = { version = "2.9.3", default-features = false }
|
tauri = { version = "2.6", default-features = false }
|
||||||
tauri-build = "2.4"
|
tauri-build = "2.3"
|
||||||
tauri-plugin = "2.4"
|
tauri-plugin = "2.3"
|
||||||
tauri-utils = "2.7"
|
tauri-utils = "2.5"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|||||||
+1
-2
@@ -3,12 +3,11 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
import eslint from '@eslint/js'
|
import eslint from '@eslint/js'
|
||||||
import { defineConfig } from 'eslint/config'
|
|
||||||
import eslintConfigPrettier from 'eslint-config-prettier'
|
import eslintConfigPrettier from 'eslint-config-prettier'
|
||||||
import eslintPluginSecurity from 'eslint-plugin-security'
|
import eslintPluginSecurity from 'eslint-plugin-security'
|
||||||
import tseslint from 'typescript-eslint'
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
export default defineConfig(
|
export default tseslint.config(
|
||||||
{
|
{
|
||||||
ignores: [
|
ignores: [
|
||||||
'**/target',
|
'**/target',
|
||||||
|
|||||||
@@ -1,86 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[2.0.28]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta
|
<meta
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover, user-scalable=0"
|
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
||||||
/>
|
/>
|
||||||
<title>Svelte + Vite App</title>
|
<title>Svelte + Vite App</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
+19
-19
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "api",
|
"name": "api",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.35",
|
"version": "2.0.28",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --clearScreen false",
|
"dev": "vite --clearScreen false",
|
||||||
@@ -10,24 +10,24 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.9.1",
|
"@tauri-apps/api": "2.7.0",
|
||||||
"@tauri-apps/plugin-barcode-scanner": "^2.4.3",
|
"@tauri-apps/plugin-barcode-scanner": "^2.4.0",
|
||||||
"@tauri-apps/plugin-biometric": "^2.3.2",
|
"@tauri-apps/plugin-biometric": "^2.3.0",
|
||||||
"@tauri-apps/plugin-cli": "^2.4.1",
|
"@tauri-apps/plugin-cli": "^2.4.0",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
"@tauri-apps/plugin-clipboard-manager": "^2.3.0",
|
||||||
"@tauri-apps/plugin-dialog": "^2.5.0",
|
"@tauri-apps/plugin-dialog": "^2.3.2",
|
||||||
"@tauri-apps/plugin-fs": "^2.4.5",
|
"@tauri-apps/plugin-fs": "^2.4.1",
|
||||||
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
||||||
"@tauri-apps/plugin-global-shortcut": "^2.3.1",
|
"@tauri-apps/plugin-global-shortcut": "^2.3.0",
|
||||||
"@tauri-apps/plugin-haptics": "^2.2.0",
|
"@tauri-apps/plugin-haptics": "^2.2.0",
|
||||||
"@tauri-apps/plugin-http": "^2.5.5",
|
"@tauri-apps/plugin-http": "^2.5.1",
|
||||||
"@tauri-apps/plugin-nfc": "^2.3.4",
|
"@tauri-apps/plugin-nfc": "^2.3.0",
|
||||||
"@tauri-apps/plugin-notification": "^2.3.3",
|
"@tauri-apps/plugin-notification": "^2.3.0",
|
||||||
"@tauri-apps/plugin-opener": "^2.5.3",
|
"@tauri-apps/plugin-opener": "^2.4.0",
|
||||||
"@tauri-apps/plugin-os": "^2.3.2",
|
"@tauri-apps/plugin-os": "^2.3.0",
|
||||||
"@tauri-apps/plugin-process": "^2.3.1",
|
"@tauri-apps/plugin-process": "^2.3.0",
|
||||||
"@tauri-apps/plugin-shell": "^2.3.4",
|
"@tauri-apps/plugin-shell": "^2.3.0",
|
||||||
"@tauri-apps/plugin-store": "^2.4.2",
|
"@tauri-apps/plugin-store": "^2.3.0",
|
||||||
"@tauri-apps/plugin-updater": "^2.9.0",
|
"@tauri-apps/plugin-updater": "^2.9.0",
|
||||||
"@tauri-apps/plugin-upload": "^2.3.0",
|
"@tauri-apps/plugin-upload": "^2.3.0",
|
||||||
"@zerodevx/svelte-json-view": "1.0.11"
|
"@zerodevx/svelte-json-view": "1.0.11"
|
||||||
@@ -36,10 +36,10 @@
|
|||||||
"@iconify-json/codicon": "^1.2.12",
|
"@iconify-json/codicon": "^1.2.12",
|
||||||
"@iconify-json/ph": "^1.2.2",
|
"@iconify-json/ph": "^1.2.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
"@sveltejs/vite-plugin-svelte": "^6.0.0",
|
||||||
"@tauri-apps/cli": "2.9.6",
|
"@tauri-apps/cli": "2.7.1",
|
||||||
"@unocss/extractor-svelte": "^66.3.3",
|
"@unocss/extractor-svelte": "^66.3.3",
|
||||||
"svelte": "^5.20.4",
|
"svelte": "^5.20.4",
|
||||||
"unocss": "^66.3.3",
|
"unocss": "^66.3.3",
|
||||||
"vite": "^7.0.7"
|
"vite": "^7.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[2.0.32]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "api"
|
name = "api"
|
||||||
publish = false
|
publish = false
|
||||||
version = "2.0.39"
|
version = "2.0.32"
|
||||||
description = "An example Tauri Application showcasing the api"
|
description = "An example Tauri Application showcasing the api"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
@@ -20,24 +20,24 @@ serde = { workspace = true }
|
|||||||
tiny_http = "0.12"
|
tiny_http = "0.12"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.8.0" }
|
tauri-plugin-log = { path = "../../../plugins/log", version = "2.6.0" }
|
||||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.5", features = [
|
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.4.1", features = [
|
||||||
"watch",
|
"watch",
|
||||||
] }
|
] }
|
||||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.2" }
|
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.3.0" }
|
||||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.5.0" }
|
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.3.2" }
|
||||||
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
||||||
"multipart",
|
"multipart",
|
||||||
"cookies",
|
"cookies",
|
||||||
], version = "2.5.5" }
|
], version = "2.5.1" }
|
||||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.3", features = [
|
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.3.0", features = [
|
||||||
"windows7-compat",
|
"windows7-compat",
|
||||||
] }
|
] }
|
||||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.2" }
|
tauri-plugin-os = { path = "../../../plugins/os", version = "2.3.0" }
|
||||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.1" }
|
tauri-plugin-process = { path = "../../../plugins/process", version = "2.3.0" }
|
||||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.5.3" }
|
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.4.0" }
|
||||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.4" }
|
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.3.0" }
|
||||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.4.2" }
|
tauri-plugin-store = { path = "../../../plugins/store", version = "2.3.0" }
|
||||||
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
|
tauri-plugin-upload = { path = "../../../plugins/upload", version = "2.3.0" }
|
||||||
|
|
||||||
[dependencies.tauri]
|
[dependencies.tauri]
|
||||||
@@ -55,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]
|
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||||
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.1" }
|
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.4.0" }
|
||||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.1" }
|
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.3.0" }
|
||||||
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.9.0" }
|
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.9.0" }
|
||||||
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
|
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
|
||||||
|
|
||||||
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
||||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.3" }
|
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.4.0" }
|
||||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.4" }
|
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.3.0" }
|
||||||
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.2" }
|
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.3.0" }
|
||||||
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.2" }
|
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.3.0" }
|
||||||
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.2" }
|
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.3.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
prod = ["tauri/custom-protocol"]
|
prod = ["tauri/custom-protocol"]
|
||||||
|
|||||||
@@ -68,9 +68,6 @@
|
|||||||
"fs:allow-rename",
|
"fs:allow-rename",
|
||||||
"fs:allow-mkdir",
|
"fs:allow-mkdir",
|
||||||
"fs:allow-remove",
|
"fs:allow-remove",
|
||||||
"fs:allow-stat",
|
|
||||||
"fs:allow-fstat",
|
|
||||||
"fs:allow-lstat",
|
|
||||||
"fs:allow-write-text-file",
|
"fs:allow-write-text-file",
|
||||||
"fs:read-meta",
|
"fs:read-meta",
|
||||||
"fs:scope-download-recursive",
|
"fs:scope-download-recursive",
|
||||||
@@ -78,9 +75,6 @@
|
|||||||
{
|
{
|
||||||
"identifier": "fs:scope-appdata-recursive",
|
"identifier": "fs:scope-appdata-recursive",
|
||||||
"allow": [
|
"allow": [
|
||||||
{
|
|
||||||
"path": "$APPDATA/db/"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "$APPDATA/db/**"
|
"path": "$APPDATA/db/**"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
namespace = "com.tauri.api"
|
namespace = "com.tauri.api"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||||
applicationId = "com.tauri.api"
|
applicationId = "com.tauri.api"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 36
|
targetSdk = 34
|
||||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:8.11.0")
|
classpath("com.android.tools.build:gradle:8.5.1")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(gradleApi())
|
compileOnly(gradleApi())
|
||||||
implementation("com.android.tools.build:gradle:8.11.0")
|
implementation("com.android.tools.build:gradle:8.5.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
let filter = null;
|
let filter = null;
|
||||||
let multiple = false;
|
let multiple = false;
|
||||||
let directory = false;
|
let directory = false;
|
||||||
let pickerMode = "";
|
|
||||||
|
|
||||||
function arrayBufferToBase64(buffer, callback) {
|
function arrayBufferToBase64(buffer, callback) {
|
||||||
var blob = new Blob([buffer], {
|
var blob = new Blob([buffer], {
|
||||||
@@ -45,13 +44,6 @@
|
|||||||
await message("Tauri is awesome!");
|
await message("Tauri is awesome!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function msgCustom(result) {
|
|
||||||
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
|
|
||||||
await message(`Tauri is: `, { buttons })
|
|
||||||
.then((res) => onMessage(`Tauri is ${res}`))
|
|
||||||
.catch(onMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
function openDialog() {
|
function openDialog() {
|
||||||
open({
|
open({
|
||||||
title: "My wonderful open dialog",
|
title: "My wonderful open dialog",
|
||||||
@@ -66,7 +58,6 @@
|
|||||||
: [],
|
: [],
|
||||||
multiple,
|
multiple,
|
||||||
directory,
|
directory,
|
||||||
pickerMode: pickerMode === "" ? undefined : pickerMode,
|
|
||||||
})
|
})
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
if (Array.isArray(res)) {
|
if (Array.isArray(res)) {
|
||||||
@@ -96,7 +87,7 @@
|
|||||||
onMessage(res);
|
onMessage(res);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(onMessage);
|
.catch(onMessage(res));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(onMessage);
|
.catch(onMessage);
|
||||||
@@ -114,7 +105,7 @@
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
})
|
})
|
||||||
.then(onMessage)
|
.then(onMessage)
|
||||||
.catch(onMessage);
|
.catch(onMessage);
|
||||||
}
|
}
|
||||||
@@ -144,28 +135,13 @@
|
|||||||
<input type="checkbox" id="dialog-directory" bind:checked={directory} />
|
<input type="checkbox" id="dialog-directory" bind:checked={directory} />
|
||||||
<label for="dialog-directory">Directory</label>
|
<label for="dialog-directory">Directory</label>
|
||||||
</div>
|
</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>
|
|
||||||
<br />
|
<br />
|
||||||
|
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
||||||
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
|
<button class="btn" id="save-dialog" on:click={saveDialog}
|
||||||
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
|
>Open save 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}
|
||||||
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
|
>Prompt (custom)</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={msg}>Message</button>
|
|
||||||
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as fs from '@tauri-apps/plugin-fs'
|
import * as fs from '@tauri-apps/plugin-fs'
|
||||||
import * as os from '@tauri-apps/plugin-os'
|
|
||||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
import { arrayBufferToBase64 } from '../lib/utils'
|
import { arrayBufferToBase64 } from '../lib/utils'
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
|
|
||||||
const { onMessage, insecureRenderHtml } = $props()
|
const { onMessage, insecureRenderHtml } = $props()
|
||||||
|
|
||||||
@@ -19,12 +18,6 @@
|
|||||||
let baseDir = $state()
|
let baseDir = $state()
|
||||||
let unwatchFn
|
let unwatchFn
|
||||||
let unwatchPath = ''
|
let unwatchPath = ''
|
||||||
let isMobile = $state(false)
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
let platform = os.platform()
|
|
||||||
isMobile = platform === 'android' || platform === 'ios'
|
|
||||||
})
|
|
||||||
|
|
||||||
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) =>
|
const dirOptions = Object.keys(fs.BaseDirectory).filter((key) =>
|
||||||
isNaN(parseInt(key))
|
isNaN(parseInt(key))
|
||||||
@@ -45,7 +38,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mkdir() {
|
function mkdir() {
|
||||||
fs.mkdir(path, { baseDir, recursive: true })
|
fs.mkdir(path, { baseDir })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
onMessage(`Created dir ${path}`)
|
onMessage(`Created dir ${path}`)
|
||||||
})
|
})
|
||||||
@@ -80,16 +73,6 @@
|
|||||||
.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() {
|
function stat() {
|
||||||
file
|
file
|
||||||
.stat()
|
.stat()
|
||||||
@@ -197,13 +180,6 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<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">
|
<div class="flex gap-1">
|
||||||
<select class="input" bind:value={baseDir}>
|
<select class="input" bind:value={baseDir}>
|
||||||
<option value={undefined} selected>None</option>
|
<option value={undefined} selected>None</option>
|
||||||
@@ -231,7 +207,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if file}
|
{#if file}
|
||||||
<div>
|
<div>
|
||||||
<button class="btn" onclick={write}>Write</button>
|
|
||||||
<button class="btn" onclick={truncate}>Truncate</button>
|
<button class="btn" onclick={truncate}>Truncate</button>
|
||||||
<button class="btn" onclick={stat}>Stat</button>
|
<button class="btn" onclick={stat}>Stat</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import { sendNotification } from '@tauri-apps/plugin-notification'
|
|
||||||
export let onMessage
|
export let onMessage
|
||||||
|
|
||||||
let sound = ''
|
|
||||||
|
|
||||||
// send the notification directly
|
// send the notification directly
|
||||||
// the backend is responsible for checking the permission
|
// the backend is responsible for checking the permission
|
||||||
function _sendNotification() {
|
function _sendNotification() {
|
||||||
sendNotification({
|
new Notification('Notification title', {
|
||||||
title: 'Notification title',
|
body: 'This is the notification body'
|
||||||
body: 'This is the notification body',
|
|
||||||
sound: sound || null
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// alternatively, check the permission ourselves
|
// alternatively, check the permission ourselves
|
||||||
function triggerNotification() {
|
function sendNotification() {
|
||||||
if (Notification.permission === 'default') {
|
if (Notification.permission === 'default') {
|
||||||
Notification.requestPermission()
|
Notification.requestPermission()
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
@@ -34,11 +29,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<input
|
<button class="btn" id="notification" on:click={sendNotification}>
|
||||||
class="input grow"
|
|
||||||
placeholder="Notification sound..."
|
|
||||||
bind:value={sound}
|
|
||||||
/>
|
|
||||||
<button class="btn" id="notification" on:click={triggerNotification}>
|
|
||||||
Send test notification
|
Send test notification
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { download, upload, HttpMethod } from '@tauri-apps/plugin-upload'
|
import { download, upload } from '@tauri-apps/plugin-upload'
|
||||||
import { open } from '@tauri-apps/plugin-dialog'
|
import { open } from '@tauri-apps/plugin-dialog'
|
||||||
import { JsonView } from '@zerodevx/svelte-json-view'
|
import { JsonView } from '@zerodevx/svelte-json-view'
|
||||||
import { appDataDir } from '@tauri-apps/api/path'
|
import { appDataDir } from '@tauri-apps/api/path'
|
||||||
@@ -16,22 +16,6 @@
|
|||||||
|
|
||||||
let uploadUrl = 'https://httpbin.org/post'
|
let uploadUrl = 'https://httpbin.org/post'
|
||||||
let uploadFilePath = ''
|
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 uploadProgress = null
|
||||||
let uploadResult = null
|
let uploadResult = null
|
||||||
let isUploading = false
|
let isUploading = false
|
||||||
@@ -213,8 +197,7 @@
|
|||||||
},
|
},
|
||||||
new Map([
|
new Map([
|
||||||
['User-Agent', 'Tauri Upload Plugin Demo']
|
['User-Agent', 'Tauri Upload Plugin Demo']
|
||||||
]),
|
])
|
||||||
uploadMethod
|
|
||||||
)
|
)
|
||||||
|
|
||||||
uploadResult = {
|
uploadResult = {
|
||||||
@@ -357,36 +340,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</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
|
<button
|
||||||
on:click={startUpload}
|
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"
|
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}
|
disabled={isUploading || !uploadUrl || !uploadFilePath}
|
||||||
>
|
>
|
||||||
{isUploading ? `Uploading (${uploadMethod})...` : `Upload File (${uploadMethod})`}
|
{isUploading ? 'Uploading...' : 'Upload File'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if uploadProgress}
|
{#if uploadProgress}
|
||||||
|
|||||||
+9
-10
@@ -11,21 +11,20 @@
|
|||||||
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.39.2",
|
"@eslint/js": "9.32.0",
|
||||||
"@rollup/plugin-node-resolve": "16.0.3",
|
"@rollup/plugin-node-resolve": "16.0.1",
|
||||||
"@rollup/plugin-terser": "0.4.4",
|
"@rollup/plugin-terser": "0.4.4",
|
||||||
"@rollup/plugin-typescript": "12.3.0",
|
"@rollup/plugin-typescript": "12.1.4",
|
||||||
"covector": "^0.12.4",
|
"covector": "^0.12.4",
|
||||||
"eslint": "9.39.2",
|
"eslint": "9.32.0",
|
||||||
"eslint-config-prettier": "10.1.8",
|
"eslint-config-prettier": "10.1.8",
|
||||||
"eslint-plugin-security": "3.0.1",
|
"eslint-plugin-security": "3.0.1",
|
||||||
"prettier": "3.7.4",
|
"prettier": "3.6.2",
|
||||||
"rollup": "4.54.0",
|
"rollup": "4.46.2",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.2",
|
||||||
"typescript-eslint": "8.50.1"
|
"typescript-eslint": "8.39.0"
|
||||||
},
|
},
|
||||||
"minimumReleaseAge": 4320,
|
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"esbuild@<0.25.0": ">=0.25.0"
|
"esbuild@<0.25.0": ">=0.25.0"
|
||||||
@@ -35,6 +34,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"pnpm": "^10.16.0"
|
"pnpm": "^10.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
# Changelog
|
# 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]
|
## \[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
|
- [`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]
|
[package]
|
||||||
name = "tauri-plugin-autostart"
|
name = "tauri-plugin-autostart"
|
||||||
version = "2.5.1"
|
version = "2.5.0"
|
||||||
description = "Automatically launch your application at startup."
|
description = "Automatically launch your application at startup."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -9,6 +9,10 @@ rust-version = { workspace = true }
|
|||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
links = "tauri-plugin-autostart"
|
links = "tauri-plugin-autostart"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
windows = { level = "full", notes = "" }
|
windows = { level = "full", notes = "" }
|
||||||
linux = { level = "full", notes = "" }
|
linux = { level = "full", notes = "" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-autostart",
|
"name": "@tauri-apps/plugin-autostart",
|
||||||
"version": "2.5.1",
|
"version": "2.5.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Tauri Programme within The Commons Conservancy"
|
"Tauri Programme within The Commons Conservancy"
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[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+
|
- [`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+
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-barcode-scanner"
|
name = "tauri-plugin-barcode-scanner"
|
||||||
version = "2.4.3"
|
version = "2.4.0"
|
||||||
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
|
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -10,6 +10,8 @@ repository = { workspace = true }
|
|||||||
links = "tauri-plugin-barcode-scanner"
|
links = "tauri-plugin-barcode-scanner"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
targets = ["x86_64-linux-android"]
|
targets = ["x86_64-linux-android"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.tauri.barcodescanner"
|
namespace = "app.tauri.barcodescanner"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
@@ -33,14 +33,16 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
val camerax_version = "1.5.1"
|
|
||||||
implementation("androidx.core:core-ktx:1.9.0")
|
implementation("androidx.core:core-ktx:1.9.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.6.0")
|
implementation("androidx.appcompat:appcompat:1.6.0")
|
||||||
implementation("com.google.android.material:material:1.7.0")
|
implementation("com.google.android.material:material:1.7.0")
|
||||||
implementation("androidx.camera:camera-core:${camerax_version}")
|
implementation("androidx.camera:camera-core:1.1.0")
|
||||||
implementation("androidx.camera:camera-camera2:${camerax_version}")
|
implementation("androidx.camera:camera-view:1.1.0")
|
||||||
implementation("androidx.camera:camera-lifecycle:${camerax_version}")
|
implementation("androidx.camera:camera-lifecycle:1.1.0")
|
||||||
implementation("androidx.camera:camera-view:${camerax_version}")
|
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("com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0")
|
implementation("com.google.android.gms:play-services-mlkit-barcode-scanning:18.1.0")
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import java.util.concurrent.ExecutionException
|
|||||||
|
|
||||||
private const val PERMISSION_ALIAS_CAMERA = "camera"
|
private const val PERMISSION_ALIAS_CAMERA = "camera"
|
||||||
private const val PERMISSION_NAME = Manifest.permission.CAMERA
|
private const val PERMISSION_NAME = Manifest.permission.CAMERA
|
||||||
|
private const val PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING"
|
||||||
|
|
||||||
@InvokeArg
|
@InvokeArg
|
||||||
class ScanOptions {
|
class ScanOptions {
|
||||||
@@ -353,6 +354,17 @@ 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")
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
@PermissionCallback
|
@PermissionCallback
|
||||||
fun cameraPermissionCallback(invoke: Invoke) {
|
fun cameraPermissionCallback(invoke: Invoke) {
|
||||||
@@ -368,7 +380,9 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
|||||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||||
} else {
|
} else {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
if (!activity.shouldShowRequestPermissionRationale(PERMISSION_NAME)) {
|
||||||
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||||
}
|
}
|
||||||
@@ -387,12 +401,20 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
|||||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||||
} else {
|
} else {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
requestPermissionForAlias(
|
if (firstPermissionRequest() || activity.shouldShowRequestPermissionRationale(
|
||||||
PERMISSION_ALIAS_CAMERA,
|
PERMISSION_NAME
|
||||||
invoke,
|
)
|
||||||
"cameraPermissionCallback"
|
) {
|
||||||
)
|
markFirstPermissionRequest()
|
||||||
return
|
requestPermissionForAlias(
|
||||||
|
PERMISSION_ALIAS_CAMERA,
|
||||||
|
invoke,
|
||||||
|
"cameraPermissionCallback"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.DENIED)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
requestPermissionResponse.put(PERMISSION_ALIAS_CAMERA, PermissionState.GRANTED)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,6 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
|||||||
if self.captureSession != nil {
|
if self.captureSession != nil {
|
||||||
self.captureSession!.stopRunning()
|
self.captureSession!.stopRunning()
|
||||||
self.cameraView.removePreviewLayer()
|
self.cameraView.removePreviewLayer()
|
||||||
self.cameraView.removeFromSuperview()
|
|
||||||
self.captureVideoPreviewLayer = nil
|
self.captureVideoPreviewLayer = nil
|
||||||
self.metaOutput = nil
|
self.metaOutput = nil
|
||||||
self.captureSession = nil
|
self.captureSession = nil
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-barcode-scanner",
|
"name": "@tauri-apps/plugin-barcode-scanner",
|
||||||
"version": "2.4.3",
|
"version": "2.4.0",
|
||||||
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
|
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -25,6 +25,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
# Changelog
|
# 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]
|
## \[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
|
- [`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]
|
[package]
|
||||||
name = "tauri-plugin-biometric"
|
name = "tauri-plugin-biometric"
|
||||||
version = "2.3.2"
|
version = "2.3.0"
|
||||||
description = "Prompt the user for biometric authentication on Android and iOS."
|
description = "Prompt the user for biometric authentication on Android and iOS."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -9,6 +9,8 @@ repository = { workspace = true }
|
|||||||
links = "tauri-plugin-biometric"
|
links = "tauri-plugin-biometric"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
targets = ["x86_64-linux-android"]
|
targets = ["x86_64-linux-android"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.tauri.biometric"
|
namespace = "app.tauri.biometric"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-biometric",
|
"name": "@tauri-apps/plugin-biometric",
|
||||||
"version": "2.3.2",
|
"version": "2.3.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Tauri Programme within The Commons Conservancy"
|
"Tauri Programme within The Commons Conservancy"
|
||||||
@@ -25,6 +25,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
# Changelog
|
# 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]
|
## \[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
|
- [`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]
|
[package]
|
||||||
name = "tauri-plugin-cli"
|
name = "tauri-plugin-cli"
|
||||||
version = "2.4.1"
|
version = "2.4.0"
|
||||||
description = "Parse arguments from your Tauri application's command line interface."
|
description = "Parse arguments from your Tauri application's command line interface."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -9,6 +9,10 @@ rust-version = { workspace = true }
|
|||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
links = "tauri-plugin-cli"
|
links = "tauri-plugin-cli"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
windows = { level = "full", notes = "" }
|
windows = { level = "full", notes = "" }
|
||||||
linux = { level = "full", notes = "" }
|
linux = { level = "full", notes = "" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-cli",
|
"name": "@tauri-apps/plugin-cli",
|
||||||
"version": "2.4.1",
|
"version": "2.4.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Tauri Programme within The Commons Conservancy"
|
"Tauri Programme within The Commons Conservancy"
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
# Changelog
|
# 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]
|
## \[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
|
- [`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]
|
[package]
|
||||||
name = "tauri-plugin-clipboard-manager"
|
name = "tauri-plugin-clipboard-manager"
|
||||||
version = "2.3.2"
|
version = "2.3.0"
|
||||||
description = "Read and write to the system clipboard."
|
description = "Read and write to the system clipboard."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -10,7 +10,8 @@ repository = { workspace = true }
|
|||||||
links = "tauri-plugin-clipboard-manager"
|
links = "tauri-plugin-clipboard-manager"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
|
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.tauri.clipboard"
|
namespace = "app.tauri.clipboard"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-clipboard-manager",
|
"name": "@tauri-apps/plugin-clipboard-manager",
|
||||||
"version": "2.3.2",
|
"version": "2.3.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Tauri Programme within The Commons Conservancy"
|
"Tauri Programme within The Commons Conservancy"
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[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
|
- [`d4f8299b`](https://github.com/tauri-apps/plugins-workspace/commit/d4f8299b12f107718c70692840a63768d65baaf9) ([#2844](https://github.com/tauri-apps/plugins-workspace/pull/2844) by [@yobson1](https://github.com/tauri-apps/plugins-workspace/../../yobson1)) Fix deep link protocol handler not set as default on linux
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-deep-link"
|
name = "tauri-plugin-deep-link"
|
||||||
version = "2.4.6"
|
version = "2.4.1"
|
||||||
description = "Set your Tauri application as the default handler for an URL"
|
description = "Set your Tauri application as the default handler for an URL"
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -10,6 +10,8 @@ repository = { workspace = true }
|
|||||||
links = "tauri-plugin-deep-link"
|
links = "tauri-plugin-deep-link"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
targets = ["x86_64-linux-android"]
|
targets = ["x86_64-linux-android"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
@@ -25,9 +27,6 @@ serde_json = { workspace = true }
|
|||||||
tauri-utils = { workspace = true }
|
tauri-utils = { workspace = true }
|
||||||
tauri-plugin = { workspace = true, features = ["build"] }
|
tauri-plugin = { workspace = true, features = ["build"] }
|
||||||
|
|
||||||
[target."cfg(target_os = \"macos\")".build-dependencies]
|
|
||||||
plist = "1"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.tauri.deep_link"
|
namespace = "app.tauri.deep_link"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|||||||
+26
-113
@@ -10,64 +10,50 @@ const COMMANDS: &[&str] = &["get_current", "register", "unregister", "is_registe
|
|||||||
|
|
||||||
// TODO: Consider using activity-alias in case users may have multiple activities in their app.
|
// TODO: Consider using activity-alias in case users may have multiple activities in their app.
|
||||||
fn intent_filter(domain: &AssociatedDomain) -> String {
|
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!(
|
format!(
|
||||||
r#"<intent-filter {auto_verify}>
|
r#"<intent-filter android:autoVerify="true">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
{schemes}
|
{}
|
||||||
{host}
|
<data android:host="{}" />
|
||||||
{domains}
|
{}
|
||||||
{path_patterns}
|
{}
|
||||||
{path_prefixes}
|
{}
|
||||||
{path_suffixes}
|
{}
|
||||||
</intent-filter>"#,
|
</intent-filter>"#,
|
||||||
schemes = domain
|
domain
|
||||||
.scheme
|
.scheme
|
||||||
.iter()
|
.iter()
|
||||||
.map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#))
|
.map(|scheme| format!(r#"<data android:scheme="{scheme}" />"#))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n "),
|
.join("\n "),
|
||||||
host = host,
|
domain.host,
|
||||||
domains = domain
|
domain
|
||||||
.path
|
.path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| format!(r#"<data android:path="{path}" />"#))
|
.map(|path| format!(r#"<data android:path="{path}" />"#))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n "),
|
.join("\n "),
|
||||||
path_patterns = domain
|
domain
|
||||||
.path_pattern
|
.path_pattern
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#))
|
.map(|pattern| format!(r#"<data android:pathPattern="{pattern}" />"#))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n "),
|
.join("\n "),
|
||||||
path_prefixes = domain
|
domain
|
||||||
.path_prefix
|
.path_prefix
|
||||||
.iter()
|
.iter()
|
||||||
.map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#))
|
.map(|prefix| format!(r#"<data android:pathPrefix="{prefix}" />"#))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n "),
|
.join("\n "),
|
||||||
path_suffixes = domain
|
domain
|
||||||
.path_suffix
|
.path_suffix
|
||||||
.iter()
|
.iter()
|
||||||
.map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#))
|
.map(|suffix| format!(r#"<data android:pathSuffix="{suffix}" />"#))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n "),
|
.join("\n "),
|
||||||
)
|
)
|
||||||
.trim()
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -82,16 +68,6 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(config) = tauri_plugin::plugin_config::<Config>("deep-link") {
|
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(
|
tauri_plugin::mobile::update_android_manifest(
|
||||||
"DEEP LINK PLUGIN",
|
"DEEP LINK PLUGIN",
|
||||||
"activity",
|
"activity",
|
||||||
@@ -104,83 +80,20 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.expect("failed to rewrite AndroidManifest.xml");
|
.expect("failed to rewrite AndroidManifest.xml");
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
// we need to ensure that the entitlements are only
|
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
||||||
// generated for explicit app links and not
|
entitlements.insert(
|
||||||
// other deep links because then they
|
"com.apple.developer.associated-domains".into(),
|
||||||
// are just going to complain and not be built or signed
|
config
|
||||||
let has_app_links = config.mobile.iter().any(|d| d.is_app_link());
|
.mobile
|
||||||
|
.into_iter()
|
||||||
if !has_app_links {
|
.map(|d| format!("applinks:{}", d.host).into())
|
||||||
tauri_plugin::mobile::update_entitlements(|entitlements| {
|
.collect::<Vec<_>>()
|
||||||
entitlements.remove("com.apple.developer.associated-domains");
|
.into(),
|
||||||
})
|
);
|
||||||
.expect("failed to update entitlements");
|
})
|
||||||
} else {
|
.expect("failed to update entitlements");
|
||||||
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,35 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[2.2.4]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "deep-link-example",
|
"name": "deep-link-example",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.2.9",
|
"version": "2.2.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -10,12 +10,12 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.9.1",
|
"@tauri-apps/api": "2.7.0",
|
||||||
"@tauri-apps/plugin-deep-link": "2.4.6"
|
"@tauri-apps/plugin-deep-link": "2.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "2.9.6",
|
"@tauri-apps/cli": "2.7.1",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^7.0.7"
|
"vite": "^7.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
namespace = "com.tauri.deep_link_example"
|
namespace = "com.tauri.deep_link_example"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||||
applicationId = "com.tauri.deep_link_example"
|
applicationId = "com.tauri.deep_link_example"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 36
|
targetSdk = 34
|
||||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||||
}
|
}
|
||||||
@@ -58,10 +58,9 @@ rust {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.webkit:webkit:1.14.0")
|
implementation("androidx.webkit:webkit:1.6.1")
|
||||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
implementation("com.google.android.material:material:1.8.0")
|
||||||
implementation("com.google.android.material:material:1.12.0")
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||||
|
|||||||
+4
-21
@@ -23,40 +23,23 @@
|
|||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
<!-- 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" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
|
||||||
<data android:scheme="http" />
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
<data android:host="fabianlars.de" />
|
<data android:host="fabianlars.de" />
|
||||||
|
|
||||||
|
|
||||||
<data android:pathPrefix="/intent" />
|
<data android:pathPrefix="/intent" />
|
||||||
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter android:autoVerify="true" >
|
<intent-filter android:autoVerify="true">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
|
||||||
<data android:scheme="http" />
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
<data android:host="tauri.app" />
|
<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>
|
</intent-filter>
|
||||||
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
<!-- DEEP LINK PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
+5
-9
@@ -1,11 +1,7 @@
|
|||||||
|
// 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
|
package com.tauri.deep_link_example
|
||||||
|
|
||||||
import android.os.Bundle
|
class MainActivity : TauriActivity()
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
|
|
||||||
class MainActivity : TauriActivity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
enableEdgeToEdge()
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:8.11.0")
|
classpath("com.android.tools.build:gradle:8.5.1")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(gradleApi())
|
compileOnly(gradleApi())
|
||||||
implementation("com.android.tools.build:gradle:8.11.0")
|
implementation("com.android.tools.build:gradle:8.5.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Tue May 10 19:22:52 CST 2022
|
#Tue May 10 19:22:52 CST 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
+77
-77
@@ -1,116 +1,116 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images": [
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size": "20x20",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-20x20@2x.png",
|
"filename": "AppIcon-20x20@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size": "20x20",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-20x20@3x.png",
|
"filename": "AppIcon-20x20@3x.png",
|
||||||
"scale" : "3x"
|
"scale": "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size": "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-29x29@2x-1.png",
|
"filename": "AppIcon-29x29@2x-1.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size": "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-29x29@3x.png",
|
"filename": "AppIcon-29x29@3x.png",
|
||||||
"scale" : "3x"
|
"scale": "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size": "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-40x40@2x.png",
|
"filename": "AppIcon-40x40@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size": "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-40x40@3x.png",
|
"filename": "AppIcon-40x40@3x.png",
|
||||||
"scale" : "3x"
|
"scale": "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size": "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-60x60@2x.png",
|
"filename": "AppIcon-60x60@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size": "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom": "iphone",
|
||||||
"filename" : "AppIcon-60x60@3x.png",
|
"filename": "AppIcon-60x60@3x.png",
|
||||||
"scale" : "3x"
|
"scale": "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size": "20x20",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-20x20@1x.png",
|
"filename": "AppIcon-20x20@1x.png",
|
||||||
"scale" : "1x"
|
"scale": "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size": "20x20",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-20x20@2x-1.png",
|
"filename": "AppIcon-20x20@2x-1.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size": "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-29x29@1x.png",
|
"filename": "AppIcon-29x29@1x.png",
|
||||||
"scale" : "1x"
|
"scale": "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size": "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-29x29@2x.png",
|
"filename": "AppIcon-29x29@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size": "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-40x40@1x.png",
|
"filename": "AppIcon-40x40@1x.png",
|
||||||
"scale" : "1x"
|
"scale": "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size": "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-40x40@2x-1.png",
|
"filename": "AppIcon-40x40@2x-1.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size": "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-76x76@1x.png",
|
"filename": "AppIcon-76x76@1x.png",
|
||||||
"scale" : "1x"
|
"scale": "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size": "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-76x76@2x.png",
|
"filename": "AppIcon-76x76@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "83.5x83.5",
|
"size": "83.5x83.5",
|
||||||
"idiom" : "ipad",
|
"idiom": "ipad",
|
||||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
"filename": "AppIcon-83.5x83.5@2x.png",
|
||||||
"scale" : "2x"
|
"scale": "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "1024x1024",
|
"size": "1024x1024",
|
||||||
"idiom" : "ios-marketing",
|
"idiom": "ios-marketing",
|
||||||
"filename" : "AppIcon-512@2x.png",
|
"filename": "AppIcon-512@2x.png",
|
||||||
"scale" : "1x"
|
"scale": "1x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info": {
|
||||||
"version" : 1,
|
"version": 1,
|
||||||
"author" : "xcode"
|
"author": "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"info" : {
|
"info": {
|
||||||
"version" : 1,
|
"version": 1,
|
||||||
"author" : "xcode"
|
"author": "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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" initialViewController="Y6W-OH-hqX">
|
<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">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17122"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
|||||||
+34
-12
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 63;
|
objectVersion = 56;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -167,8 +167,6 @@
|
|||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = "deep-link-example_iOS";
|
name = "deep-link-example_iOS";
|
||||||
packageProductDependencies = (
|
|
||||||
);
|
|
||||||
productName = "deep-link-example_iOS";
|
productName = "deep-link-example_iOS";
|
||||||
productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */;
|
productReference = 1CAAFA750FD735A285DC1238 /* deep-link-example.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
@@ -191,7 +189,6 @@
|
|||||||
en,
|
en,
|
||||||
);
|
);
|
||||||
mainGroup = 1DC58B1705AA3ECC6B887FE7;
|
mainGroup = 1DC58B1705AA3ECC6B887FE7;
|
||||||
minimizedProjectReferenceProxies = 1;
|
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
@@ -230,6 +227,7 @@
|
|||||||
outputPaths = (
|
outputPaths = (
|
||||||
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
|
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
|
||||||
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
|
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
|
||||||
|
"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a",
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
@@ -316,13 +314,18 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ARCHS = arm64;
|
ARCHS = (
|
||||||
|
arm64,
|
||||||
|
"arm64-sim",
|
||||||
|
);
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||||
|
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"\".\"",
|
"\".\"",
|
||||||
@@ -332,6 +335,13 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@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]" = (
|
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||||
@@ -350,7 +360,7 @@
|
|||||||
PRODUCT_NAME = "deep-link-example";
|
PRODUCT_NAME = "deep-link-example";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALID_ARCHS = arm64;
|
VALID_ARCHS = "arm64 arm64-sim";
|
||||||
};
|
};
|
||||||
name = debug;
|
name = debug;
|
||||||
};
|
};
|
||||||
@@ -414,13 +424,18 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
ARCHS = arm64;
|
ARCHS = (
|
||||||
|
arm64,
|
||||||
|
"arm64-sim",
|
||||||
|
);
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "deep-link-example_iOS/deep-link-example_iOS.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
DEVELOPMENT_TEAM = "Q93MBH6S2F";
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
DEVELOPMENT_TEAM = Q93MBH6S2F;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
"EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64;
|
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
|
||||||
|
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"\".\"",
|
"\".\"",
|
||||||
@@ -430,6 +445,13 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@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]" = (
|
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
|
||||||
@@ -448,7 +470,7 @@
|
|||||||
PRODUCT_NAME = "deep-link-example";
|
PRODUCT_NAME = "deep-link-example";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALID_ARCHS = arm64;
|
VALID_ARCHS = "arm64 arm64-sim";
|
||||||
};
|
};
|
||||||
name = release;
|
name = release;
|
||||||
};
|
};
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>
|
||||||
+1
-12
@@ -15,7 +15,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.1.0</string>
|
<string>0.0.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.1.0</string>
|
<string>0.1.0</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
@@ -40,16 +40,5 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleURLTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>taurideeplink</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleURLName</key>
|
|
||||||
<string>taurideeplink</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
name: deep-link-example
|
name: deep-link-example
|
||||||
options:
|
options:
|
||||||
bundleIdPrefix: com.tauri.deep-link-example
|
bundleIdPrefix: com.tauri.deep-link-example
|
||||||
@@ -12,6 +16,7 @@ settingGroups:
|
|||||||
base:
|
base:
|
||||||
PRODUCT_NAME: deep-link-example
|
PRODUCT_NAME: deep-link-example
|
||||||
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example
|
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.deep-link-example
|
||||||
|
DEVELOPMENT_TEAM: Q93MBH6S2F
|
||||||
targetTemplates:
|
targetTemplates:
|
||||||
app:
|
app:
|
||||||
type: application
|
type: application
|
||||||
@@ -51,8 +56,8 @@ targets:
|
|||||||
- UIInterfaceOrientationPortraitUpsideDown
|
- UIInterfaceOrientationPortraitUpsideDown
|
||||||
- UIInterfaceOrientationLandscapeLeft
|
- UIInterfaceOrientationLandscapeLeft
|
||||||
- UIInterfaceOrientationLandscapeRight
|
- UIInterfaceOrientationLandscapeRight
|
||||||
CFBundleShortVersionString: 0.1.0
|
CFBundleShortVersionString: 0.0.0
|
||||||
CFBundleVersion: '0.1.0'
|
CFBundleVersion: 0.0.0
|
||||||
entitlements:
|
entitlements:
|
||||||
path: deep-link-example_iOS/deep-link-example_iOS.entitlements
|
path: deep-link-example_iOS/deep-link-example_iOS.entitlements
|
||||||
scheme:
|
scheme:
|
||||||
@@ -62,12 +67,14 @@ targets:
|
|||||||
settings:
|
settings:
|
||||||
base:
|
base:
|
||||||
ENABLE_BITCODE: false
|
ENABLE_BITCODE: false
|
||||||
ARCHS: [arm64]
|
ARCHS: [arm64, arm64-sim]
|
||||||
VALID_ARCHS: arm64
|
VALID_ARCHS: arm64 arm64-sim
|
||||||
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=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]: $(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
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
|
||||||
EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64
|
EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64
|
||||||
|
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
|
||||||
groups: [app]
|
groups: [app]
|
||||||
dependencies:
|
dependencies:
|
||||||
- framework: libapp.a
|
- framework: libapp.a
|
||||||
@@ -86,3 +93,4 @@ targets:
|
|||||||
outputFiles:
|
outputFiles:
|
||||||
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
|
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
|
||||||
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
|
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
|
||||||
|
- $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a
|
||||||
|
|||||||
@@ -35,9 +35,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"host": "tauri.app"
|
"host": "tauri.app"
|
||||||
},
|
|
||||||
{
|
|
||||||
"scheme": ["taurideeplink"]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"desktop": {
|
"desktop": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-deep-link",
|
"name": "@tauri-apps/plugin-deep-link",
|
||||||
"version": "2.4.6",
|
"version": "2.4.1",
|
||||||
"description": "Set your Tauri application as the default handler for an URL",
|
"description": "Set your Tauri application as the default handler for an URL",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -25,9 +25,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@tauri-apps/cli": "2.9.6"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ use tauri_utils::config::DeepLinkProtocol;
|
|||||||
pub struct AssociatedDomain {
|
pub struct AssociatedDomain {
|
||||||
#[serde(default = "default_schemes")]
|
#[serde(default = "default_schemes")]
|
||||||
pub scheme: Vec<String>,
|
pub scheme: Vec<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(deserialize_with = "deserialize_associated_host")]
|
||||||
|
pub host: String,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub path: Vec<String>,
|
pub path: Vec<String>,
|
||||||
#[serde(default, alias = "path-pattern", rename = "pathPattern")]
|
#[serde(default, alias = "path-pattern", rename = "pathPattern")]
|
||||||
@@ -21,41 +23,6 @@ pub struct AssociatedDomain {
|
|||||||
pub path_prefix: Vec<String>,
|
pub path_prefix: Vec<String>,
|
||||||
#[serde(default, alias = "path-suffix", rename = "pathSuffix")]
|
#[serde(default, alias = "path-suffix", rename = "pathSuffix")]
|
||||||
pub path_suffix: Vec<String>,
|
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
|
// TODO: Consider removing this in v3
|
||||||
@@ -63,19 +30,18 @@ fn default_schemes() -> Vec<String> {
|
|||||||
vec!["https".to_string(), "http".to_string()]
|
vec!["https".to_string(), "http".to_string()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
fn deserialize_associated_host<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let opt = Option::<String>::deserialize(deserializer)?;
|
let host = String::deserialize(deserializer)?;
|
||||||
if let Some(ref host) = opt {
|
if let Some((scheme, _host)) = host.split_once("://") {
|
||||||
if let Some((scheme, _)) = host.split_once("://") {
|
Err(serde::de::Error::custom(format!(
|
||||||
return Err(serde::de::Error::custom(format!(
|
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
||||||
"host `{host}` cannot start with a scheme, please remove the `{scheme}://` prefix"
|
)))
|
||||||
)));
|
} else {
|
||||||
}
|
Ok(host)
|
||||||
}
|
}
|
||||||
Ok(opt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
|
|||||||
@@ -28,16 +28,6 @@ pub enum Error {
|
|||||||
PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError),
|
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 {
|
impl Serialize for Error {
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -254,7 +254,6 @@ mod imp {
|
|||||||
///
|
///
|
||||||
/// ## Platform-specific:
|
/// ## 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`).
|
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||||
pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> {
|
pub fn register<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<()> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -293,7 +292,6 @@ mod imp {
|
|||||||
.unwrap_or_else(|| bin.into_os_string())
|
.unwrap_or_else(|| bin.into_os_string())
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string();
|
.to_string();
|
||||||
let qualified_exec = format!("{} %u", exec);
|
|
||||||
|
|
||||||
let target = self.app.path().data_dir()?.join("applications");
|
let target = self.app.path().data_dir()?.join("applications");
|
||||||
|
|
||||||
@@ -305,28 +303,12 @@ mod imp {
|
|||||||
|
|
||||||
if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) {
|
if let Ok(mut desktop_file) = ini::Ini::load_from_file(&target_file) {
|
||||||
if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) {
|
if let Some(section) = desktop_file.section_mut(Some("Desktop Entry")) {
|
||||||
|
// it's ok to remove it - we only write to the file if it's missing
|
||||||
|
// and in that case we include old_mimes
|
||||||
let old_mimes = section.remove("MimeType").unwrap_or_default();
|
let 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) {
|
if !old_mimes.split(';').any(|mime| mime == mime_type) {
|
||||||
section.append("MimeType", format!("{mime_type};{old_mimes}"));
|
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)?;
|
desktop_file.write_to_file(&target_file)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,7 +323,7 @@ mod imp {
|
|||||||
.product_name
|
.product_name
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| file_name.clone()),
|
.unwrap_or_else(|| file_name.clone()),
|
||||||
qualified_exec = qualified_exec,
|
exec = exec,
|
||||||
mime_type = mime_type
|
mime_type = mime_type
|
||||||
)
|
)
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
@@ -350,15 +332,11 @@ mod imp {
|
|||||||
|
|
||||||
Command::new("update-desktop-database")
|
Command::new("update-desktop-database")
|
||||||
.arg(target)
|
.arg(target)
|
||||||
.status()
|
.status()?;
|
||||||
.inspect_err(crate::error::inspect_command_error(
|
|
||||||
"update-desktop-database",
|
|
||||||
))?;
|
|
||||||
|
|
||||||
Command::new("xdg-mime")
|
Command::new("xdg-mime")
|
||||||
.args(["default", &file_name, mime_type.as_str()])
|
.args(["default", &file_name, mime_type.as_str()])
|
||||||
.status()
|
.status()?;
|
||||||
.inspect_err(crate::error::inspect_command_error("xdg-mime"))?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -427,7 +405,6 @@ mod imp {
|
|||||||
///
|
///
|
||||||
/// ## Platform-specific:
|
/// ## Platform-specific:
|
||||||
///
|
///
|
||||||
/// - **Linux**: Needs the `xdg-mime` command available on the system.
|
|
||||||
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
/// - **macOS / Android / iOS**: Unsupported, will return [`Error::UnsupportedPlatform`](`crate::Error::UnsupportedPlatform`).
|
||||||
pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> {
|
pub fn is_registered<S: AsRef<str>>(&self, _protocol: S) -> crate::Result<bool> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -462,8 +439,7 @@ mod imp {
|
|||||||
"default",
|
"default",
|
||||||
&format!("x-scheme-handler/{}", _protocol.as_ref()),
|
&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))
|
Ok(String::from_utf8_lossy(&output.stdout).contains(&file_name))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name={name}
|
Name={name}
|
||||||
Exec={qualified_exec}
|
Exec={exec} %u
|
||||||
Terminal=false
|
Terminal=false
|
||||||
MimeType={mime_type}
|
MimeType={mime_type}
|
||||||
NoDisplay=true
|
NoDisplay=true
|
||||||
@@ -1,43 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[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]
|
## \[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.
|
- [`af08c66f`](https://github.com/tauri-apps/plugins-workspace/commit/af08c66faafe0dffc4b0a80aef030cd3f0f89a9c) ([#2871](https://github.com/tauri-apps/plugins-workspace/pull/2871) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused the file picker not to open on Android when extension filters were set.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-dialog"
|
name = "tauri-plugin-dialog"
|
||||||
version = "2.5.0"
|
version = "2.3.2"
|
||||||
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
|
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -9,12 +9,9 @@ rust-version = { workspace = true }
|
|||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
links = "tauri-plugin-dialog"
|
links = "tauri-plugin-dialog"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["gtk3"]
|
|
||||||
xdg-portal = ["rfd/xdg-portal", "rfd/tokio", "rfd/wayland"]
|
|
||||||
gtk3 = ["rfd/gtk3"]
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
|
targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
@@ -37,14 +34,15 @@ tauri = { workspace = true }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
tauri-plugin-fs = { path = "../fs", version = "2.4.5" }
|
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
|
||||||
|
|
||||||
[target.'cfg(target_os = "ios")'.dependencies]
|
[target.'cfg(target_os = "ios")'.dependencies]
|
||||||
tauri = { workspace = true, features = ["wry"] }
|
tauri = { workspace = true, features = ["wry"] }
|
||||||
|
|
||||||
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||||
rfd = { version = "0.16", default-features = false, features = [
|
rfd = { version = "0.15", default-features = false, features = [
|
||||||
|
"tokio",
|
||||||
|
"gtk3",
|
||||||
"common-controls-v6",
|
"common-controls-v6",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
raw-window-handle = "0.6"
|
raw-window-handle = "0.6"
|
||||||
|
|||||||
@@ -31,24 +31,6 @@ tauri-plugin-dialog = "2.0.0"
|
|||||||
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
|
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Linux XDG Desktop Portal Support
|
|
||||||
|
|
||||||
By default, this plugin uses gtk to show dialogs, however since `v2.5.0` you can switch to using [XDG Desktop Portal](https://flatpak.github.io/xdg-desktop-portal/) by adding the following to your `Cargo.toml` file:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
tauri-plugin-dialog = { version = "2.5.0", default-features = false, features = ["xdg-portal"] }
|
|
||||||
# alternatively with Git:
|
|
||||||
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2", default-features = false, features = ["xdg-portal"] }
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Do note if you use the `xdg-portal` feature, you need to ensure that [`zenity`](https://gitlab.gnome.org/GNOME/zenity) and an [XDG Desktop Portal backend](https://flatpak.github.io/xdg-desktop-portal#using-portals) is installed with your program.
|
|
||||||
|
|
||||||
For more information, see [XDG Desktop Portal documentation](https://flatpak.github.io/xdg-desktop-portal/) and [`rfd` documentation](https://docs.rs/rfd/latest/rfd#xdg-desktop-portal-backend).
|
|
||||||
|
|
||||||
### JavaScript
|
|
||||||
|
|
||||||
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "app.tauri.dialog"
|
namespace = "app.tauri.dialog"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class Filter {
|
|||||||
class FilePickerOptions {
|
class FilePickerOptions {
|
||||||
lateinit var filters: Array<Filter>
|
lateinit var filters: Array<Filter>
|
||||||
var multiple: Boolean? = null
|
var multiple: Boolean? = null
|
||||||
var pickerMode: String? = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@InvokeArg
|
@InvokeArg
|
||||||
@@ -39,7 +38,6 @@ class MessageOptions {
|
|||||||
var title: String? = null
|
var title: String? = null
|
||||||
lateinit var message: String
|
lateinit var message: String
|
||||||
var okButtonLabel: String? = null
|
var okButtonLabel: String? = null
|
||||||
var noButtonLabel: String? = null
|
|
||||||
var cancelButtonLabel: String? = null
|
var cancelButtonLabel: String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,19 +60,10 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
// TODO: ACTION_OPEN_DOCUMENT ??
|
// TODO: ACTION_OPEN_DOCUMENT ??
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
intent.type = "*/*"
|
||||||
|
|
||||||
if (args.pickerMode == "image") {
|
if (parsedTypes.isNotEmpty()) {
|
||||||
intent.type = "image/*"
|
|
||||||
} else if (args.pickerMode == "video") {
|
|
||||||
intent.type = "video/*"
|
|
||||||
} else if (args.pickerMode == "media") {
|
|
||||||
intent.type = "*/*"
|
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("video/*", "image/*"))
|
|
||||||
} else if (parsedTypes.isNotEmpty()) {
|
|
||||||
intent.type = "*/*"
|
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
|
||||||
} else {
|
|
||||||
intent.type = "*/*"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, args.multiple ?: false)
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, args.multiple ?: false)
|
||||||
@@ -150,8 +139,9 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val handler = { value: String ->
|
val handler = { cancelled: Boolean, value: Boolean ->
|
||||||
val ret = JSObject()
|
val ret = JSObject()
|
||||||
|
ret.put("cancelled", cancelled)
|
||||||
ret.put("value", value)
|
ret.put("value", value)
|
||||||
invoke.resolve(ret)
|
invoke.resolve(ret)
|
||||||
}
|
}
|
||||||
@@ -163,34 +153,24 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
if (args.title != null) {
|
if (args.title != null) {
|
||||||
builder.setTitle(args.title)
|
builder.setTitle(args.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
val okButtonLabel = args.okButtonLabel ?: "Ok"
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.setMessage(args.message)
|
.setMessage(args.message)
|
||||||
.setPositiveButton(okButtonLabel) { dialog, _ ->
|
.setPositiveButton(
|
||||||
|
args.okButtonLabel ?: "OK"
|
||||||
|
) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
handler(okButtonLabel)
|
handler(false, true)
|
||||||
}
|
}
|
||||||
.setOnCancelListener { dialog ->
|
.setOnCancelListener { dialog ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
handler(args.cancelButtonLabel ?: "Cancel")
|
handler(true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.noButtonLabel != null) {
|
|
||||||
builder.setNeutralButton(args.noButtonLabel) { dialog, _ ->
|
|
||||||
dialog.dismiss()
|
|
||||||
handler(args.noButtonLabel!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.cancelButtonLabel != null) {
|
if (args.cancelButtonLabel != null) {
|
||||||
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
|
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
handler(args.cancelButtonLabel!!)
|
handler(false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val dialog = builder.create()
|
val dialog = builder.create()
|
||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}function e(t){if(void 0!==t)return"string"==typeof t?t:"ok"in t&&"cancel"in t?{OkCancelCustom:[t.ok,t.cancel]}:"yes"in t&&"no"in t&&"cancel"in t?{YesNoCancelCustom:[t.yes,t.no,t.cancel]}:"ok"in t?{OkCustom:t.ok}:void 0}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,yesButtonLabel:o?.okLabel?.toString(),noButtonLabel:o?.cancelLabel?.toString()})},t.confirm=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,okButtonLabel:o?.okLabel?.toString(),cancelButtonLabel:o?.cancelLabel?.toString()})},t.message=async function(t,o){const i="string"==typeof o?{title:o}:o;return n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),buttons:e(i?.buttons)})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,yesButtonLabel:i?.okLabel?.toString(),noButtonLabel:i?.cancelLabel?.toString()})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),cancelButtonLabel:i?.cancelLabel?.toString()})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
|
||||||
|
|||||||
@@ -14,16 +14,6 @@ interface DialogFilter {
|
|||||||
name: string
|
name: string
|
||||||
/**
|
/**
|
||||||
* Extensions to filter, without a `.` prefix.
|
* Extensions to filter, without a `.` prefix.
|
||||||
*
|
|
||||||
* **Note:** Mobile platforms have different APIs for filtering that may not support extensions.
|
|
||||||
* iOS: Extensions are supported in the document picker, but not in the media picker.
|
|
||||||
* Android: Extensions are not supported.
|
|
||||||
*
|
|
||||||
* For these platforms, MIME types are the primary way to filter files, as opposed to extensions.
|
|
||||||
* This means the string values here labeled as `extensions` may also be a MIME type.
|
|
||||||
* This property name of `extensions` is being kept for backwards compatibility, but this may be revisited to
|
|
||||||
* specify the difference between extension or MIME type filtering.
|
|
||||||
*
|
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* extensions: ['svg', 'png']
|
* extensions: ['svg', 'png']
|
||||||
@@ -40,14 +30,7 @@ interface DialogFilter {
|
|||||||
interface OpenDialogOptions {
|
interface OpenDialogOptions {
|
||||||
/** The title of the dialog window (desktop only). */
|
/** The title of the dialog window (desktop only). */
|
||||||
title?: string
|
title?: string
|
||||||
/**
|
/** The filters of the dialog. */
|
||||||
* The filters of the dialog.
|
|
||||||
* On mobile platforms, if either:
|
|
||||||
* A) the {@linkcode pickerMode} is set to `media`, `image`, or `video`
|
|
||||||
* -- or --
|
|
||||||
* B) the filters include **only** either image or video mime types, the media picker will be displayed.
|
|
||||||
* Otherwise, the document picker will be displayed.
|
|
||||||
*/
|
|
||||||
filters?: DialogFilter[]
|
filters?: DialogFilter[]
|
||||||
/**
|
/**
|
||||||
* Initial directory or file path.
|
* Initial directory or file path.
|
||||||
@@ -69,13 +52,6 @@ interface OpenDialogOptions {
|
|||||||
recursive?: boolean
|
recursive?: boolean
|
||||||
/** Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** */
|
/** Whether to allow creating directories in the dialog. Enabled by default. **macOS Only** */
|
||||||
canCreateDirectories?: boolean
|
canCreateDirectories?: boolean
|
||||||
/**
|
|
||||||
* The preferred mode of the dialog.
|
|
||||||
* This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
|
|
||||||
* If not provided, the dialog will automatically choose the best mode based on the MIME types or extensions of the {@linkcode filters}.
|
|
||||||
* On desktop, this option is ignored.
|
|
||||||
*/
|
|
||||||
pickerMode?: PickerMode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,90 +77,6 @@ interface SaveDialogOptions {
|
|||||||
canCreateDirectories?: boolean
|
canCreateDirectories?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The preferred mode of the dialog.
|
|
||||||
* This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
|
|
||||||
* On desktop, this option is ignored.
|
|
||||||
* If not provided, the dialog will automatically choose the best mode based on the MIME types or extensions of the {@linkcode filters}.
|
|
||||||
*
|
|
||||||
* **Note:** This option is only supported on iOS 14 and above. This parameter is ignored on iOS 13 and below.
|
|
||||||
*/
|
|
||||||
export type PickerMode = 'document' | 'media' | 'image' | 'video'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default buttons for a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogDefaultButtons =
|
|
||||||
| 'Ok'
|
|
||||||
| 'OkCancel'
|
|
||||||
| 'YesNo'
|
|
||||||
| 'YesNoCancel'
|
|
||||||
|
|
||||||
/** All possible button keys. */
|
|
||||||
type ButtonKey = 'ok' | 'cancel' | 'yes' | 'no'
|
|
||||||
|
|
||||||
/** Ban everything except a set of keys. */
|
|
||||||
type BanExcept<Allowed extends ButtonKey> = Partial<
|
|
||||||
Record<Exclude<ButtonKey, Allowed>, never>
|
|
||||||
>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Yes, No and Cancel buttons of a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogButtonsYesNoCancel = {
|
|
||||||
/** The Yes button. */
|
|
||||||
yes: string
|
|
||||||
/** The No button. */
|
|
||||||
no: string
|
|
||||||
/** The Cancel button. */
|
|
||||||
cancel: string
|
|
||||||
} & BanExcept<'yes' | 'no' | 'cancel'>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Ok and Cancel buttons of a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogButtonsOkCancel = {
|
|
||||||
/** The Ok button. */
|
|
||||||
ok: string
|
|
||||||
/** The Cancel button. */
|
|
||||||
cancel: string
|
|
||||||
} & BanExcept<'ok' | 'cancel'>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Ok button of a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogButtonsOk = {
|
|
||||||
/** The Ok button. */
|
|
||||||
ok: string
|
|
||||||
} & BanExcept<'ok'>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom buttons for a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogCustomButtons =
|
|
||||||
| MessageDialogButtonsYesNoCancel
|
|
||||||
| MessageDialogButtonsOkCancel
|
|
||||||
| MessageDialogButtonsOk
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The buttons of a message dialog.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogButtons =
|
|
||||||
| MessageDialogDefaultButtons
|
|
||||||
| MessageDialogCustomButtons
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@@ -193,58 +85,8 @@ interface MessageDialogOptions {
|
|||||||
title?: string
|
title?: string
|
||||||
/** The kind of the dialog. Defaults to `info`. */
|
/** The kind of the dialog. Defaults to `info`. */
|
||||||
kind?: 'info' | 'warning' | 'error'
|
kind?: 'info' | 'warning' | 'error'
|
||||||
/**
|
/** The label of the confirm button. */
|
||||||
* The label of the Ok button.
|
|
||||||
*
|
|
||||||
* @deprecated Use {@linkcode MessageDialogOptions.buttons} instead.
|
|
||||||
*/
|
|
||||||
okLabel?: string
|
okLabel?: string
|
||||||
/**
|
|
||||||
* The buttons of the dialog.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```ts
|
|
||||||
* // Use system default buttons texts
|
|
||||||
* await message('Hello World!', { buttons: 'Ok' })
|
|
||||||
* await message('Hello World!', { buttons: 'OkCancel' })
|
|
||||||
*
|
|
||||||
* // Or with custom button texts
|
|
||||||
* await message('Hello World!', { buttons: { ok: 'Yes!' } })
|
|
||||||
* await message('Take on the task?', {
|
|
||||||
* buttons: { ok: 'Accept', cancel: 'Cancel' }
|
|
||||||
* })
|
|
||||||
* await message('Show the file content?', {
|
|
||||||
* buttons: { yes: 'Show content', no: 'Show in folder', cancel: 'Cancel' }
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
buttons?: MessageDialogButtons
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal function to convert the buttons to the Rust type.
|
|
||||||
*/
|
|
||||||
function buttonsToRust(buttons: MessageDialogButtons | undefined) {
|
|
||||||
if (buttons === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof buttons === 'string') {
|
|
||||||
return buttons
|
|
||||||
} else if ('ok' in buttons && 'cancel' in buttons) {
|
|
||||||
return { OkCancelCustom: [buttons.ok, buttons.cancel] }
|
|
||||||
} else if ('yes' in buttons && 'no' in buttons && 'cancel' in buttons) {
|
|
||||||
return {
|
|
||||||
YesNoCancelCustom: [buttons.yes, buttons.no, buttons.cancel]
|
|
||||||
}
|
|
||||||
} else if ('ok' in buttons) {
|
|
||||||
return { OkCustom: buttons.ok }
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfirmDialogOptions {
|
interface ConfirmDialogOptions {
|
||||||
@@ -360,16 +202,6 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
|
|||||||
return await invoke('plugin:dialog|save', { options })
|
return await invoke('plugin:dialog|save', { options })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of a message dialog.
|
|
||||||
*
|
|
||||||
* The result is a string if the dialog has custom buttons,
|
|
||||||
* otherwise it is one of the default buttons.
|
|
||||||
*
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a message dialog with an `Ok` button.
|
* Shows a message dialog with an `Ok` button.
|
||||||
* @example
|
* @example
|
||||||
@@ -390,15 +222,13 @@ export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
|
|||||||
async function message(
|
async function message(
|
||||||
message: string,
|
message: string,
|
||||||
options?: string | MessageDialogOptions
|
options?: string | MessageDialogOptions
|
||||||
): Promise<MessageDialogResult> {
|
): Promise<void> {
|
||||||
const opts = typeof options === 'string' ? { title: options } : options
|
const opts = typeof options === 'string' ? { title: options } : options
|
||||||
|
await invoke('plugin:dialog|message', {
|
||||||
return invoke<MessageDialogResult>('plugin:dialog|message', {
|
|
||||||
message: message.toString(),
|
message: message.toString(),
|
||||||
title: opts?.title?.toString(),
|
title: opts?.title?.toString(),
|
||||||
kind: opts?.kind,
|
kind: opts?.kind,
|
||||||
okButtonLabel: opts?.okLabel?.toString(),
|
okButtonLabel: opts?.okLabel?.toString()
|
||||||
buttons: buttonsToRust(opts?.buttons)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import PhotosUI
|
|||||||
import SwiftRs
|
import SwiftRs
|
||||||
import Tauri
|
import Tauri
|
||||||
import UIKit
|
import UIKit
|
||||||
import UniformTypeIdentifiers
|
|
||||||
import WebKit
|
import WebKit
|
||||||
|
|
||||||
enum FilePickerEvent {
|
enum FilePickerEvent {
|
||||||
@@ -21,7 +20,6 @@ struct MessageDialogOptions: Decodable {
|
|||||||
var title: String?
|
var title: String?
|
||||||
let message: String
|
let message: String
|
||||||
var okButtonLabel: String?
|
var okButtonLabel: String?
|
||||||
var noButtonLabel: String?
|
|
||||||
var cancelButtonLabel: String?
|
var cancelButtonLabel: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +31,6 @@ struct FilePickerOptions: Decodable {
|
|||||||
var multiple: Bool?
|
var multiple: Bool?
|
||||||
var filters: [Filter]?
|
var filters: [Filter]?
|
||||||
var defaultPath: String?
|
var defaultPath: String?
|
||||||
var pickerMode: PickerMode?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SaveFileDialogOptions: Decodable {
|
struct SaveFileDialogOptions: Decodable {
|
||||||
@@ -41,13 +38,6 @@ struct SaveFileDialogOptions: Decodable {
|
|||||||
var defaultPath: String?
|
var defaultPath: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PickerMode: String, Decodable {
|
|
||||||
case document
|
|
||||||
case media
|
|
||||||
case image
|
|
||||||
case video
|
|
||||||
}
|
|
||||||
|
|
||||||
class DialogPlugin: Plugin {
|
class DialogPlugin: Plugin {
|
||||||
|
|
||||||
var filePickerController: FilePickerController!
|
var filePickerController: FilePickerController!
|
||||||
@@ -61,6 +51,26 @@ class DialogPlugin: Plugin {
|
|||||||
@objc public func showFilePicker(_ invoke: Invoke) throws {
|
@objc public func showFilePicker(_ invoke: Invoke) throws {
|
||||||
let args = try invoke.parseArgs(FilePickerOptions.self)
|
let args = try invoke.parseArgs(FilePickerOptions.self)
|
||||||
|
|
||||||
|
let parsedTypes = parseFiltersOption(args.filters ?? [])
|
||||||
|
|
||||||
|
var isMedia = !parsedTypes.isEmpty
|
||||||
|
var uniqueMimeType: Bool? = nil
|
||||||
|
var mimeKind: String? = nil
|
||||||
|
if !parsedTypes.isEmpty {
|
||||||
|
uniqueMimeType = true
|
||||||
|
for mime in parsedTypes {
|
||||||
|
let kind = mime.components(separatedBy: "/")[0]
|
||||||
|
if kind != "image" && kind != "video" {
|
||||||
|
isMedia = false
|
||||||
|
}
|
||||||
|
if mimeKind == nil {
|
||||||
|
mimeKind = kind
|
||||||
|
} else if mimeKind != kind {
|
||||||
|
uniqueMimeType = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onFilePickerResult = { (event: FilePickerEvent) -> Void in
|
onFilePickerResult = { (event: FilePickerEvent) -> Void in
|
||||||
switch event {
|
switch event {
|
||||||
case .selected(let urls):
|
case .selected(let urls):
|
||||||
@@ -70,57 +80,51 @@ class DialogPlugin: Plugin {
|
|||||||
case .error(let error):
|
case .error(let error):
|
||||||
invoke.reject(error)
|
invoke.reject(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(iOS 14, *) {
|
if uniqueMimeType == true || isMedia {
|
||||||
let parsedTypes = parseFiltersOption(args.filters ?? [])
|
DispatchQueue.main.async {
|
||||||
|
if #available(iOS 14, *) {
|
||||||
let mimeKinds = Set(parsedTypes.compactMap { $0.preferredMIMEType?.components(separatedBy: "/")[0] })
|
|
||||||
let filtersIncludeImage = mimeKinds.contains("image")
|
|
||||||
let filtersIncludeVideo = mimeKinds.contains("video")
|
|
||||||
let filtersIncludeNonMedia = mimeKinds.contains(where: { $0 != "image" && $0 != "video" })
|
|
||||||
|
|
||||||
// If the picker mode is media, images, or videos, we always want to show the media picker regardless of what's in the filters.
|
|
||||||
// Otherwise, if the filters A) do not include non-media types and B) include either image or video, we want to show the media picker.
|
|
||||||
if args.pickerMode == .media
|
|
||||||
|| args.pickerMode == .image
|
|
||||||
|| args.pickerMode == .video
|
|
||||||
|| (!filtersIncludeNonMedia && (filtersIncludeImage || filtersIncludeVideo)) {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
||||||
configuration.selectionLimit = (args.multiple ?? false) ? 0 : 1
|
configuration.selectionLimit = (args.multiple ?? false) ? 0 : 1
|
||||||
|
|
||||||
// If the filters include image or video, use the appropriate filter.
|
if uniqueMimeType == true {
|
||||||
// If both are true, don't define a filter, which means we will display all media.
|
if mimeKind == "image" {
|
||||||
if args.pickerMode == .image || (filtersIncludeImage && !filtersIncludeVideo) {
|
configuration.filter = .images
|
||||||
configuration.filter = .images
|
} else if mimeKind == "video" {
|
||||||
} else if args.pickerMode == .video || (filtersIncludeVideo && !filtersIncludeImage) {
|
configuration.filter = .videos
|
||||||
configuration.filter = .videos
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let picker = PHPickerViewController(configuration: configuration)
|
let picker = PHPickerViewController(configuration: configuration)
|
||||||
picker.delegate = self.filePickerController
|
picker.delegate = self.filePickerController
|
||||||
picker.modalPresentationStyle = .fullScreen
|
picker.modalPresentationStyle = .fullScreen
|
||||||
self.presentViewController(picker)
|
self.presentViewController(picker)
|
||||||
}
|
} else {
|
||||||
} else {
|
let picker = UIImagePickerController()
|
||||||
DispatchQueue.main.async {
|
picker.delegate = self.filePickerController
|
||||||
// The UTType.item is the catch-all, allowing for any file type to be selected.
|
|
||||||
let contentTypes = parsedTypes.isEmpty ? [UTType.item] : parsedTypes
|
if uniqueMimeType == true && mimeKind == "image" {
|
||||||
let picker: UIDocumentPickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
|
picker.sourceType = .photoLibrary
|
||||||
|
|
||||||
if let defaultPath = args.defaultPath {
|
|
||||||
picker.directoryURL = URL(string: defaultPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
picker.delegate = self.filePickerController
|
picker.sourceType = .photoLibrary
|
||||||
picker.allowsMultipleSelection = args.multiple ?? false
|
|
||||||
picker.modalPresentationStyle = .fullScreen
|
picker.modalPresentationStyle = .fullScreen
|
||||||
self.presentViewController(picker)
|
self.presentViewController(picker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showFilePickerLegacy(args: args)
|
let documentTypes = parsedTypes.isEmpty ? ["public.data"] : parsedTypes
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
|
||||||
|
if let defaultPath = args.defaultPath {
|
||||||
|
picker.directoryURL = URL(string: defaultPath)
|
||||||
|
}
|
||||||
|
picker.delegate = self.filePickerController
|
||||||
|
picker.allowsMultipleSelection = args.multiple ?? false
|
||||||
|
picker.modalPresentationStyle = .fullScreen
|
||||||
|
self.presentViewController(picker)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,80 +172,19 @@ class DialogPlugin: Plugin {
|
|||||||
self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
|
self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 14, *)
|
private func parseFiltersOption(_ filters: [Filter]) -> [String] {
|
||||||
private func parseFiltersOption(_ filters: [Filter]) -> [UTType] {
|
|
||||||
var parsedTypes: [UTType] = []
|
|
||||||
for filter in filters {
|
|
||||||
for ext in filter.extensions ?? [] {
|
|
||||||
// We need to support extensions as well as MIME types.
|
|
||||||
if let utType = UTType(mimeType: ext) {
|
|
||||||
parsedTypes.append(utType)
|
|
||||||
} else if let utType = UTType(filenameExtension: ext) {
|
|
||||||
parsedTypes.append(utType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsedTypes
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is only used for iOS < 14, and should be removed if/when the deployment target is raised to 14.
|
|
||||||
private func showFilePickerLegacy(args: FilePickerOptions) {
|
|
||||||
let parsedTypes = parseFiltersOptionLegacy(args.filters ?? [])
|
|
||||||
|
|
||||||
var filtersIncludeImage: Bool = false
|
|
||||||
var filtersIncludeVideo: Bool = false
|
|
||||||
var filtersIncludeNonMedia: Bool = false
|
|
||||||
|
|
||||||
if !parsedTypes.isEmpty {
|
|
||||||
let mimeKinds = Set(parsedTypes.map { $0.components(separatedBy: "/")[0] })
|
|
||||||
filtersIncludeImage = mimeKinds.contains("image")
|
|
||||||
filtersIncludeVideo = mimeKinds.contains("video")
|
|
||||||
filtersIncludeNonMedia = mimeKinds.contains(where: { $0 != "image" && $0 != "video" })
|
|
||||||
}
|
|
||||||
|
|
||||||
if !filtersIncludeNonMedia && (filtersIncludeImage || filtersIncludeVideo) {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let picker = UIImagePickerController()
|
|
||||||
picker.delegate = self.filePickerController
|
|
||||||
|
|
||||||
if filtersIncludeImage && !filtersIncludeVideo {
|
|
||||||
picker.sourceType = .photoLibrary
|
|
||||||
}
|
|
||||||
|
|
||||||
picker.modalPresentationStyle = .fullScreen
|
|
||||||
self.presentViewController(picker)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let documentTypes = parsedTypes.isEmpty ? ["public.data"] : parsedTypes
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
|
|
||||||
if let defaultPath = args.defaultPath {
|
|
||||||
picker.directoryURL = URL(string: defaultPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
picker.delegate = self.filePickerController
|
|
||||||
picker.allowsMultipleSelection = args.multiple ?? false
|
|
||||||
picker.modalPresentationStyle = .fullScreen
|
|
||||||
self.presentViewController(picker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This function is only used for iOS < 14, and should be removed if/when the deployment target is raised to 14.
|
|
||||||
private func parseFiltersOptionLegacy(_ filters: [Filter]) -> [String] {
|
|
||||||
var parsedTypes: [String] = []
|
var parsedTypes: [String] = []
|
||||||
for filter in filters {
|
for filter in filters {
|
||||||
for ext in filter.extensions ?? [] {
|
for ext in filter.extensions ?? [] {
|
||||||
guard
|
guard
|
||||||
let utType: String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String?
|
let utType: String = UTTypeCreatePreferredIdentifierForTag(
|
||||||
|
kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String?
|
||||||
else {
|
else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parsedTypes.append(utType)
|
parsedTypes.append(utType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedTypes
|
return parsedTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,37 +200,35 @@ class DialogPlugin: Plugin {
|
|||||||
let alert = UIAlertController(
|
let alert = UIAlertController(
|
||||||
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
|
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
|
||||||
|
|
||||||
if let cancelButtonLabel = args.cancelButtonLabel {
|
let cancelButtonLabel = args.cancelButtonLabel ?? ""
|
||||||
|
if !cancelButtonLabel.isEmpty {
|
||||||
alert.addAction(
|
alert.addAction(
|
||||||
UIAlertAction(
|
UIAlertAction(
|
||||||
title: cancelButtonLabel, style: UIAlertAction.Style.default,
|
title: cancelButtonLabel, style: UIAlertAction.Style.default,
|
||||||
handler: { (_) -> Void in
|
handler: { (_) -> Void in
|
||||||
invoke.resolve(["value": cancelButtonLabel])
|
Logger.error("cancel")
|
||||||
}
|
|
||||||
)
|
invoke.resolve([
|
||||||
)
|
"value": false,
|
||||||
|
"cancelled": false,
|
||||||
|
])
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let noButtonLabel = args.noButtonLabel {
|
let okButtonLabel = args.okButtonLabel ?? (cancelButtonLabel.isEmpty ? "OK" : "")
|
||||||
|
if !okButtonLabel.isEmpty {
|
||||||
alert.addAction(
|
alert.addAction(
|
||||||
UIAlertAction(
|
UIAlertAction(
|
||||||
title: noButtonLabel, style: UIAlertAction.Style.default,
|
title: okButtonLabel, style: UIAlertAction.Style.default,
|
||||||
handler: { (_) -> Void in
|
handler: { (_) -> Void in
|
||||||
invoke.resolve(["value": noButtonLabel])
|
Logger.error("ok")
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let okButtonLabel = args.okButtonLabel ?? "Ok"
|
invoke.resolve([
|
||||||
alert.addAction(
|
"value": true,
|
||||||
UIAlertAction(
|
"cancelled": false,
|
||||||
title: okButtonLabel, style: UIAlertAction.Style.default,
|
])
|
||||||
handler: { (_) -> Void in
|
}))
|
||||||
invoke.resolve(["value": okButtonLabel])
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
manager.viewController?.present(alert, animated: true, completion: nil)
|
manager.viewController?.present(alert, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-dialog",
|
"name": "@tauri-apps/plugin-dialog",
|
||||||
"version": "2.5.0",
|
"version": "2.3.2",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Tauri Programme within The Commons Conservancy"
|
"Tauri Programme within The Commons Conservancy"
|
||||||
@@ -24,6 +24,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use tauri::{command, Manager, Runtime, State, Window};
|
|||||||
use tauri_plugin_fs::FsExt;
|
use tauri_plugin_fs::FsExt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dialog, FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogButtons,
|
Dialog, FileDialogBuilder, FilePath, MessageDialogButtons, MessageDialogKind, Result, CANCEL,
|
||||||
MessageDialogKind, MessageDialogResult, PickerMode, Result, CANCEL, NO, OK, YES,
|
NO, OK, YES,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -56,13 +56,6 @@ pub struct OpenDialogOptions {
|
|||||||
recursive: bool,
|
recursive: bool,
|
||||||
/// Whether to allow creating directories in the dialog **macOS Only**
|
/// Whether to allow creating directories in the dialog **macOS Only**
|
||||||
can_create_directories: Option<bool>,
|
can_create_directories: Option<bool>,
|
||||||
/// The preferred mode of the dialog.
|
|
||||||
/// This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
|
|
||||||
/// On desktop, this option is ignored.
|
|
||||||
/// If not provided, the dialog will automatically choose the best mode based on the MIME types of the filters.
|
|
||||||
#[serde(default)]
|
|
||||||
#[cfg_attr(mobile, allow(dead_code))]
|
|
||||||
picker_mode: Option<PickerMode>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The options for the save dialog API.
|
/// The options for the save dialog API.
|
||||||
@@ -134,9 +127,6 @@ pub(crate) async fn open<R: Runtime>(
|
|||||||
if let Some(can) = options.can_create_directories {
|
if let Some(can) = options.can_create_directories {
|
||||||
dialog_builder = dialog_builder.set_can_create_directories(can);
|
dialog_builder = dialog_builder.set_can_create_directories(can);
|
||||||
}
|
}
|
||||||
if let Some(picker_mode) = options.picker_mode {
|
|
||||||
dialog_builder = dialog_builder.set_picker_mode(picker_mode);
|
|
||||||
}
|
|
||||||
for filter in options.filters {
|
for filter in options.filters {
|
||||||
let extensions: Vec<&str> = filter.extensions.iter().map(|s| &**s).collect();
|
let extensions: Vec<&str> = filter.extensions.iter().map(|s| &**s).collect();
|
||||||
dialog_builder = dialog_builder.add_filter(filter.name, &extensions);
|
dialog_builder = dialog_builder.add_filter(filter.name, &extensions);
|
||||||
@@ -258,7 +248,7 @@ fn message_dialog<R: Runtime>(
|
|||||||
message: String,
|
message: String,
|
||||||
kind: Option<MessageDialogKind>,
|
kind: Option<MessageDialogKind>,
|
||||||
buttons: MessageDialogButtons,
|
buttons: MessageDialogButtons,
|
||||||
) -> MessageDialogBuilder<R> {
|
) -> bool {
|
||||||
let mut builder = dialog.message(message);
|
let mut builder = dialog.message(message);
|
||||||
|
|
||||||
builder = builder.buttons(buttons);
|
builder = builder.buttons(buttons);
|
||||||
@@ -276,7 +266,7 @@ fn message_dialog<R: Runtime>(
|
|||||||
builder = builder.kind(kind);
|
builder = builder.kind(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder
|
builder.blocking_show()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@@ -287,15 +277,19 @@ pub(crate) async fn message<R: Runtime>(
|
|||||||
message: String,
|
message: String,
|
||||||
kind: Option<MessageDialogKind>,
|
kind: Option<MessageDialogKind>,
|
||||||
ok_button_label: Option<String>,
|
ok_button_label: Option<String>,
|
||||||
buttons: Option<MessageDialogButtons>,
|
) -> Result<bool> {
|
||||||
) -> Result<MessageDialogResult> {
|
Ok(message_dialog(
|
||||||
let buttons = buttons.unwrap_or(if let Some(ok_button_label) = ok_button_label {
|
window,
|
||||||
MessageDialogButtons::OkCustom(ok_button_label)
|
dialog,
|
||||||
} else {
|
title,
|
||||||
MessageDialogButtons::Ok
|
message,
|
||||||
});
|
kind,
|
||||||
|
if let Some(ok_button_label) = ok_button_label {
|
||||||
Ok(message_dialog(window, dialog, title, message, kind, buttons).blocking_show_with_result())
|
MessageDialogButtons::OkCustom(ok_button_label)
|
||||||
|
} else {
|
||||||
|
MessageDialogButtons::Ok
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@@ -308,7 +302,7 @@ pub(crate) async fn ask<R: Runtime>(
|
|||||||
yes_button_label: Option<String>,
|
yes_button_label: Option<String>,
|
||||||
no_button_label: Option<String>,
|
no_button_label: Option<String>,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let dialog = message_dialog(
|
Ok(message_dialog(
|
||||||
window,
|
window,
|
||||||
dialog,
|
dialog,
|
||||||
title,
|
title,
|
||||||
@@ -324,9 +318,7 @@ pub(crate) async fn ask<R: Runtime>(
|
|||||||
} else {
|
} else {
|
||||||
MessageDialogButtons::YesNo
|
MessageDialogButtons::YesNo
|
||||||
},
|
},
|
||||||
);
|
))
|
||||||
|
|
||||||
Ok(dialog.blocking_show())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@@ -339,7 +331,7 @@ pub(crate) async fn confirm<R: Runtime>(
|
|||||||
ok_button_label: Option<String>,
|
ok_button_label: Option<String>,
|
||||||
cancel_button_label: Option<String>,
|
cancel_button_label: Option<String>,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let dialog = message_dialog(
|
Ok(message_dialog(
|
||||||
window,
|
window,
|
||||||
dialog,
|
dialog,
|
||||||
title,
|
title,
|
||||||
@@ -355,7 +347,5 @@ pub(crate) async fn confirm<R: Runtime>(
|
|||||||
} else {
|
} else {
|
||||||
MessageDialogButtons::OkCancel
|
MessageDialogButtons::OkCancel
|
||||||
},
|
},
|
||||||
);
|
))
|
||||||
|
|
||||||
Ok(dialog.blocking_show())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use rfd::{AsyncFileDialog, AsyncMessageDialog};
|
|||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
||||||
|
|
||||||
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder};
|
use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder, OK};
|
||||||
|
|
||||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||||
app: &AppHandle<R>,
|
app: &AppHandle<R>,
|
||||||
@@ -115,10 +115,6 @@ impl From<MessageDialogButtons> for rfd::MessageButtons {
|
|||||||
MessageDialogButtons::YesNo => Self::YesNo,
|
MessageDialogButtons::YesNo => Self::YesNo,
|
||||||
MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok),
|
MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok),
|
||||||
MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel),
|
MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel),
|
||||||
MessageDialogButtons::YesNoCancel => Self::YesNoCancel,
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
|
|
||||||
Self::YesNoCancelCustom(yes, no, cancel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,46 +208,28 @@ pub fn save_file<R: Runtime, F: FnOnce(Option<FilePath>) + Send + 'static>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a message dialog
|
/// Shows a message dialog
|
||||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(MessageDialogResult) + Send + 'static>(
|
pub fn show_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
||||||
dialog: MessageDialogBuilder<R>,
|
dialog: MessageDialogBuilder<R>,
|
||||||
callback: F,
|
f: F,
|
||||||
) {
|
) {
|
||||||
let f = move |res: rfd::MessageDialogResult| callback(res.into());
|
use rfd::MessageDialogResult;
|
||||||
|
|
||||||
|
let ok_label = match &dialog.buttons {
|
||||||
|
MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
|
||||||
|
MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let f = move |res| {
|
||||||
|
f(match res {
|
||||||
|
MessageDialogResult::Ok | MessageDialogResult::Yes => true,
|
||||||
|
MessageDialogResult::Custom(s) => ok_label.map_or(s == OK, |ok_label| ok_label == s),
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
let handle = dialog.dialog.app_handle().to_owned();
|
let handle = dialog.dialog.app_handle().to_owned();
|
||||||
let _ = handle.run_on_main_thread(move || {
|
let _ = handle.run_on_main_thread(move || {
|
||||||
let buttons = dialog.buttons.clone();
|
|
||||||
let dialog = AsyncMessageDialog::from(dialog).show();
|
let dialog = AsyncMessageDialog::from(dialog).show();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || f(tauri::async_runtime::block_on(dialog)));
|
||||||
let result = tauri::async_runtime::block_on(dialog);
|
|
||||||
// on Linux rfd does not return rfd::MessageDialogResult::Custom, so we must map manually
|
|
||||||
let result = match (result, buttons) {
|
|
||||||
(rfd::MessageDialogResult::Ok, MessageDialogButtons::OkCustom(s)) => {
|
|
||||||
rfd::MessageDialogResult::Custom(s)
|
|
||||||
}
|
|
||||||
(
|
|
||||||
rfd::MessageDialogResult::Ok,
|
|
||||||
MessageDialogButtons::OkCancelCustom(ok, _cancel),
|
|
||||||
) => rfd::MessageDialogResult::Custom(ok),
|
|
||||||
(
|
|
||||||
rfd::MessageDialogResult::Cancel,
|
|
||||||
MessageDialogButtons::OkCancelCustom(_ok, cancel),
|
|
||||||
) => rfd::MessageDialogResult::Custom(cancel),
|
|
||||||
(
|
|
||||||
rfd::MessageDialogResult::Yes,
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(yes, _no, _cancel),
|
|
||||||
) => rfd::MessageDialogResult::Custom(yes),
|
|
||||||
(
|
|
||||||
rfd::MessageDialogResult::No,
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(_yes, no, _cancel),
|
|
||||||
) => rfd::MessageDialogResult::Custom(no),
|
|
||||||
(
|
|
||||||
rfd::MessageDialogResult::Cancel,
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(_yes, _no, cancel),
|
|
||||||
) => rfd::MessageDialogResult::Custom(cancel),
|
|
||||||
(result, _) => result,
|
|
||||||
};
|
|
||||||
f(result);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-107
@@ -9,7 +9,7 @@
|
|||||||
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Serialize;
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
plugin::{Builder, TauriPlugin},
|
||||||
Manager, Runtime,
|
Manager, Runtime,
|
||||||
@@ -44,15 +44,6 @@ pub use desktop::Dialog;
|
|||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
pub use mobile::Dialog;
|
pub use mobile::Dialog;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum PickerMode {
|
|
||||||
Document,
|
|
||||||
Media,
|
|
||||||
Image,
|
|
||||||
Video,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) const OK: &str = "Ok";
|
pub(crate) const OK: &str = "Ok";
|
||||||
pub(crate) const CANCEL: &str = "Cancel";
|
pub(crate) const CANCEL: &str = "Cancel";
|
||||||
pub(crate) const YES: &str = "Yes";
|
pub(crate) const YES: &str = "Yes";
|
||||||
@@ -225,7 +216,6 @@ pub(crate) struct MessageDialogPayload<'a> {
|
|||||||
message: &'a String,
|
message: &'a String,
|
||||||
kind: &'a MessageDialogKind,
|
kind: &'a MessageDialogKind,
|
||||||
ok_button_label: Option<&'a str>,
|
ok_button_label: Option<&'a str>,
|
||||||
no_button_label: Option<&'a str>,
|
|
||||||
cancel_button_label: Option<&'a str>,
|
cancel_button_label: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,17 +238,13 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
|||||||
|
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
pub(crate) fn payload(&self) -> MessageDialogPayload<'_> {
|
pub(crate) fn payload(&self) -> MessageDialogPayload<'_> {
|
||||||
let (ok_button_label, no_button_label, cancel_button_label) = match &self.buttons {
|
let (ok_button_label, cancel_button_label) = match &self.buttons {
|
||||||
MessageDialogButtons::Ok => (Some(OK), None, None),
|
MessageDialogButtons::Ok => (Some(OK), None),
|
||||||
MessageDialogButtons::OkCancel => (Some(OK), None, Some(CANCEL)),
|
MessageDialogButtons::OkCancel => (Some(OK), Some(CANCEL)),
|
||||||
MessageDialogButtons::YesNo => (Some(YES), Some(NO), None),
|
MessageDialogButtons::YesNo => (Some(YES), Some(NO)),
|
||||||
MessageDialogButtons::YesNoCancel => (Some(YES), Some(NO), Some(CANCEL)),
|
MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), Some(CANCEL)),
|
||||||
MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), None, None),
|
|
||||||
MessageDialogButtons::OkCancelCustom(ok, cancel) => {
|
MessageDialogButtons::OkCancelCustom(ok, cancel) => {
|
||||||
(Some(ok.as_str()), None, Some(cancel.as_str()))
|
(Some(ok.as_str()), Some(cancel.as_str()))
|
||||||
}
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
|
|
||||||
(Some(yes.as_str()), Some(no.as_str()), Some(cancel.as_str()))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
MessageDialogPayload {
|
MessageDialogPayload {
|
||||||
@@ -266,7 +252,6 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
|||||||
message: &self.message,
|
message: &self.message,
|
||||||
kind: &self.kind,
|
kind: &self.kind,
|
||||||
ok_button_label,
|
ok_button_label,
|
||||||
no_button_label,
|
|
||||||
cancel_button_label,
|
cancel_button_label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,55 +295,16 @@ impl<R: Runtime> MessageDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a message dialog
|
/// Shows a message dialog
|
||||||
///
|
|
||||||
/// Returns `true` if the user pressed the OK/Yes button,
|
|
||||||
pub fn show<F: FnOnce(bool) + Send + 'static>(self, f: F) {
|
pub fn show<F: FnOnce(bool) + Send + 'static>(self, f: F) {
|
||||||
let ok_label = match &self.buttons {
|
|
||||||
MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
|
|
||||||
MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
|
|
||||||
MessageDialogButtons::YesNoCancelCustom(yes, _, _) => Some(yes.clone()),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
show_message_dialog(self, move |res| {
|
|
||||||
let sucess = match res {
|
|
||||||
MessageDialogResult::Ok | MessageDialogResult::Yes => true,
|
|
||||||
MessageDialogResult::Custom(s) => {
|
|
||||||
ok_label.map_or(s == OK, |ok_label| ok_label == s)
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
f(sucess)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shows a message dialog and returns the button that was pressed.
|
|
||||||
///
|
|
||||||
/// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
|
|
||||||
pub fn show_with_result<F: FnOnce(MessageDialogResult) + Send + 'static>(self, f: F) {
|
|
||||||
show_message_dialog(self, f)
|
show_message_dialog(self, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a message dialog.
|
/// Shows a message dialog.
|
||||||
///
|
|
||||||
/// Returns `true` if the user pressed the OK/Yes button,
|
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread context.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
pub fn blocking_show(self) -> bool {
|
pub fn blocking_show(self) -> bool {
|
||||||
blocking_fn!(self, show)
|
blocking_fn!(self, show)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a message dialog and returns the button that was pressed.
|
|
||||||
///
|
|
||||||
/// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
|
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
|
||||||
/// and should *NOT* be used when running on the main thread context.
|
|
||||||
pub fn blocking_show_with_result(self) -> MessageDialogResult {
|
|
||||||
blocking_fn!(self, show_with_result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub(crate) struct Filter {
|
pub(crate) struct Filter {
|
||||||
@@ -378,7 +324,6 @@ pub struct FileDialogBuilder<R: Runtime> {
|
|||||||
pub(crate) file_name: Option<String>,
|
pub(crate) file_name: Option<String>,
|
||||||
pub(crate) title: Option<String>,
|
pub(crate) title: Option<String>,
|
||||||
pub(crate) can_create_directories: Option<bool>,
|
pub(crate) can_create_directories: Option<bool>,
|
||||||
pub(crate) picker_mode: Option<PickerMode>,
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
pub(crate) parent: Option<crate::desktop::WindowHandle>,
|
pub(crate) parent: Option<crate::desktop::WindowHandle>,
|
||||||
}
|
}
|
||||||
@@ -390,7 +335,6 @@ pub(crate) struct FileDialogPayload<'a> {
|
|||||||
file_name: &'a Option<String>,
|
file_name: &'a Option<String>,
|
||||||
filters: &'a Vec<Filter>,
|
filters: &'a Vec<Filter>,
|
||||||
multiple: bool,
|
multiple: bool,
|
||||||
picker_mode: &'a Option<PickerMode>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// raw window handle :(
|
// raw window handle :(
|
||||||
@@ -406,7 +350,6 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
file_name: None,
|
file_name: None,
|
||||||
title: None,
|
title: None,
|
||||||
can_create_directories: None,
|
can_create_directories: None,
|
||||||
picker_mode: None,
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
parent: None,
|
parent: None,
|
||||||
}
|
}
|
||||||
@@ -418,7 +361,6 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
file_name: &self.file_name,
|
file_name: &self.file_name,
|
||||||
filters: &self.filters,
|
filters: &self.filters,
|
||||||
multiple,
|
multiple,
|
||||||
picker_mode: &self.picker_mode,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,21 +421,11 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the picker mode of the dialog.
|
|
||||||
/// This is meant for mobile platforms (iOS and Android) which have distinct file and media pickers.
|
|
||||||
/// On desktop, this option is ignored.
|
|
||||||
/// If not provided, the dialog will automatically choose the best mode based on the MIME types of the filters.
|
|
||||||
pub fn set_picker_mode(mut self, mode: PickerMode) -> Self {
|
|
||||||
self.picker_mode.replace(mode);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shows the dialog to select a single file.
|
/// Shows the dialog to select a single file.
|
||||||
///
|
|
||||||
/// This is not a blocking operation,
|
/// This is not a blocking operation,
|
||||||
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
||||||
///
|
///
|
||||||
/// See [`Self::blocking_pick_file`] for a blocking version for use in other contexts.
|
/// For usage in other contexts such as commands, prefer [`Self::pick_file`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -513,12 +445,9 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select multiple files.
|
/// Shows the dialog to select multiple files.
|
||||||
///
|
|
||||||
/// This is not a blocking operation,
|
/// This is not a blocking operation,
|
||||||
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
||||||
///
|
///
|
||||||
/// See [`Self::blocking_pick_files`] for a blocking version for use in other contexts.
|
|
||||||
///
|
|
||||||
/// # Reading the files
|
/// # Reading the files
|
||||||
///
|
///
|
||||||
/// The file paths cannot be read directly on Android as they are behind a content URI.
|
/// The file paths cannot be read directly on Android as they are behind a content URI.
|
||||||
@@ -561,12 +490,9 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select a single folder.
|
/// Shows the dialog to select a single folder.
|
||||||
///
|
|
||||||
/// This is not a blocking operation,
|
/// This is not a blocking operation,
|
||||||
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
||||||
///
|
///
|
||||||
/// See [`Self::blocking_pick_folder`] for a blocking version for use in other contexts.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -586,12 +512,9 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select multiple folders.
|
/// Shows the dialog to select multiple folders.
|
||||||
///
|
|
||||||
/// This is not a blocking operation,
|
/// This is not a blocking operation,
|
||||||
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
||||||
///
|
///
|
||||||
/// See [`Self::blocking_pick_folders`] for a blocking version for use in other contexts.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -615,8 +538,6 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
/// This is not a blocking operation,
|
/// This is not a blocking operation,
|
||||||
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
/// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
||||||
///
|
///
|
||||||
/// See [`Self::blocking_save_file`] for a blocking version for use in other contexts.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -638,11 +559,8 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
/// Blocking APIs.
|
/// Blocking APIs.
|
||||||
impl<R: Runtime> FileDialogBuilder<R> {
|
impl<R: Runtime> FileDialogBuilder<R> {
|
||||||
/// Shows the dialog to select a single file.
|
/// Shows the dialog to select a single file.
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
///
|
|
||||||
/// See [`Self::pick_file`] for a non-blocking version for use in main-thread contexts.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -660,11 +578,8 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select multiple files.
|
/// Shows the dialog to select multiple files.
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
///
|
|
||||||
/// See [`Self::pick_files`] for a non-blocking version for use in main-thread contexts.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -682,11 +597,8 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select a single folder.
|
/// Shows the dialog to select a single folder.
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
///
|
|
||||||
/// See [`Self::pick_folder`] for a non-blocking version for use in main-thread contexts.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -705,11 +617,8 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to select multiple folders.
|
/// Shows the dialog to select multiple folders.
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
///
|
|
||||||
/// See [`Self::pick_folders`] for a non-blocking version for use in main-thread contexts.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@@ -728,11 +637,8 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the dialog to save a file.
|
/// Shows the dialog to save a file.
|
||||||
///
|
|
||||||
/// This is a blocking operation,
|
/// This is a blocking operation,
|
||||||
/// and should *NOT* be used when running on the main thread.
|
/// and should *NOT* be used when running on the main thread context.
|
||||||
///
|
|
||||||
/// See [`Self::save_file`] for a non-blocking version for use in main-thread contexts.
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use tauri::{
|
|||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
|
use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder};
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
const PLUGIN_IDENTIFIER: &str = "app.tauri.dialog";
|
const PLUGIN_IDENTIFIER: &str = "app.tauri.dialog";
|
||||||
@@ -107,11 +107,13 @@ pub fn save_file<R: Runtime, F: FnOnce(Option<FilePath>) + Send + 'static>(
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ShowMessageDialogResponse {
|
struct ShowMessageDialogResponse {
|
||||||
value: String,
|
#[allow(dead_code)]
|
||||||
|
cancelled: bool,
|
||||||
|
value: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows a message dialog
|
/// Shows a message dialog
|
||||||
pub fn show_message_dialog<R: Runtime, F: FnOnce(MessageDialogResult) + Send + 'static>(
|
pub fn show_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
||||||
dialog: MessageDialogBuilder<R>,
|
dialog: MessageDialogBuilder<R>,
|
||||||
f: F,
|
f: F,
|
||||||
) {
|
) {
|
||||||
@@ -120,8 +122,6 @@ pub fn show_message_dialog<R: Runtime, F: FnOnce(MessageDialogResult) + Send + '
|
|||||||
.dialog
|
.dialog
|
||||||
.0
|
.0
|
||||||
.run_mobile_plugin::<ShowMessageDialogResponse>("showMessageDialog", dialog.payload());
|
.run_mobile_plugin::<ShowMessageDialogResponse>("showMessageDialog", dialog.payload());
|
||||||
|
f(res.map(|r| r.value).unwrap_or_default())
|
||||||
let res = res.map(|res| res.value.into());
|
|
||||||
f(res.unwrap_or_default())
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||||||
|
|
||||||
/// Types of message, ask and confirm dialogs.
|
/// Types of message, ask and confirm dialogs.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum MessageDialogKind {
|
pub enum MessageDialogKind {
|
||||||
/// Information dialog.
|
/// Information dialog.
|
||||||
#[default]
|
|
||||||
Info,
|
Info,
|
||||||
/// Warning dialog.
|
/// Warning dialog.
|
||||||
Warning,
|
Warning,
|
||||||
@@ -17,6 +16,12 @@ pub enum MessageDialogKind {
|
|||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MessageDialogKind {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for MessageDialogKind {
|
impl<'de> Deserialize<'de> for MessageDialogKind {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -47,7 +52,7 @@ impl Serialize for MessageDialogKind {
|
|||||||
|
|
||||||
/// Set of button that will be displayed on the dialog
|
/// Set of button that will be displayed on the dialog
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub enum MessageDialogButtons {
|
pub enum MessageDialogButtons {
|
||||||
#[default]
|
#[default]
|
||||||
/// A single `Ok` button with OS default dialog text
|
/// A single `Ok` button with OS default dialog text
|
||||||
@@ -56,49 +61,8 @@ pub enum MessageDialogButtons {
|
|||||||
OkCancel,
|
OkCancel,
|
||||||
/// 2 buttons `Yes` and `No` with OS default dialog texts
|
/// 2 buttons `Yes` and `No` with OS default dialog texts
|
||||||
YesNo,
|
YesNo,
|
||||||
/// 3 buttons `Yes`, `No` and `Cancel` with OS default dialog texts
|
|
||||||
YesNoCancel,
|
|
||||||
/// A single `Ok` button with custom text
|
/// A single `Ok` button with custom text
|
||||||
OkCustom(String),
|
OkCustom(String),
|
||||||
/// 2 buttons `Ok` and `Cancel` with custom texts
|
/// 2 buttons `Ok` and `Cancel` with custom texts
|
||||||
OkCancelCustom(String, String),
|
OkCancelCustom(String, String),
|
||||||
/// 3 buttons `Yes`, `No` and `Cancel` with custom texts
|
|
||||||
YesNoCancelCustom(String, String, String),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of a message dialog
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
|
||||||
pub enum MessageDialogResult {
|
|
||||||
Yes,
|
|
||||||
No,
|
|
||||||
Ok,
|
|
||||||
#[default]
|
|
||||||
Cancel,
|
|
||||||
#[serde(untagged)]
|
|
||||||
Custom(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(desktop)]
|
|
||||||
impl From<rfd::MessageDialogResult> for MessageDialogResult {
|
|
||||||
fn from(result: rfd::MessageDialogResult) -> Self {
|
|
||||||
match result {
|
|
||||||
rfd::MessageDialogResult::Yes => Self::Yes,
|
|
||||||
rfd::MessageDialogResult::No => Self::No,
|
|
||||||
rfd::MessageDialogResult::Ok => Self::Ok,
|
|
||||||
rfd::MessageDialogResult::Cancel => Self::Cancel,
|
|
||||||
rfd::MessageDialogResult::Custom(s) => Self::Custom(s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for MessageDialogResult {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
match value.as_str() {
|
|
||||||
"Yes" => Self::Yes,
|
|
||||||
"No" => Self::No,
|
|
||||||
"Ok" => Self::Ok,
|
|
||||||
"Cancel" => Self::Cancel,
|
|
||||||
_ => Self::Custom(value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,5 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## \[2.4.5]
|
|
||||||
|
|
||||||
- [`521cd8b3`](https://github.com/tauri-apps/plugins-workspace/commit/521cd8b372c862d96b1637775710e4d7cf2443e2) ([#3155](https://github.com/tauri-apps/plugins-workspace/pull/3155) by [@EliasStar](https://github.com/tauri-apps/plugins-workspace/../../EliasStar)) Fix off by one error in the implementation of readTextFileLines causing all lines to end with an (additional) null byte.
|
|
||||||
Issue: [#3154](https://github.com/tauri-apps/plugins-workspace/issues/3154)
|
|
||||||
PR: [#3155](https://github.com/tauri-apps/plugins-workspace/pull/3155)
|
|
||||||
|
|
||||||
## \[2.4.4]
|
|
||||||
|
|
||||||
- [`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.3]
|
|
||||||
|
|
||||||
- [`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.
|
|
||||||
- [`6b5b1053`](https://github.com/tauri-apps/plugins-workspace/commit/6b5b1053ba8aeb789dd5cb5fb05b7e98f3b8de0b) ([#1939](https://github.com/tauri-apps/plugins-workspace/pull/1939) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Enhance error messages.
|
|
||||||
|
|
||||||
## \[2.4.2]
|
|
||||||
|
|
||||||
- [`4eb36b0f`](https://github.com/tauri-apps/plugins-workspace/commit/4eb36b0ff57acb0bb1b911c583efa3bf2f56aa32) ([#2907](https://github.com/tauri-apps/plugins-workspace/pull/2907) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fixed calling `writeFile` with `data: ReadableStream` throws `Invalid argument`
|
|
||||||
- [`515182a1`](https://github.com/tauri-apps/plugins-workspace/commit/515182a179d4439079b2b7f6927555ba5ab0b035) ([#2915](https://github.com/tauri-apps/plugins-workspace/pull/2915) by [@samhinshaw](https://github.com/tauri-apps/plugins-workspace/../../samhinshaw)) `readFile` now returns a more specific type `Promise<Uint8Array<ArrayBuffer>>` instead of the default `Promise<Uint8Array<ArrayBufferLike>`
|
|
||||||
|
|
||||||
## \[2.4.1]
|
## \[2.4.1]
|
||||||
|
|
||||||
- [`44a1f659`](https://github.com/tauri-apps/plugins-workspace/commit/44a1f659125a341191420e650608b0b6ff316a0e) ([#2846](https://github.com/tauri-apps/plugins-workspace/pull/2846) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `writeFile` doesn't create a new file by default when the data is a `ReadableStream`
|
- [`44a1f659`](https://github.com/tauri-apps/plugins-workspace/commit/44a1f659125a341191420e650608b0b6ff316a0e) ([#2846](https://github.com/tauri-apps/plugins-workspace/pull/2846) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `writeFile` doesn't create a new file by default when the data is a `ReadableStream`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-fs"
|
name = "tauri-plugin-fs"
|
||||||
version = "2.4.5"
|
version = "2.4.1"
|
||||||
description = "Access the file system."
|
description = "Access the file system."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -9,6 +9,10 @@ rust-version = { workspace = true }
|
|||||||
repository = { workspace = true }
|
repository = { workspace = true }
|
||||||
links = "tauri-plugin-fs"
|
links = "tauri-plugin-fs"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
rustc-args = ["--cfg", "docsrs"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
[package.metadata.platforms.support]
|
[package.metadata.platforms.support]
|
||||||
windows = { level = "full", notes = "Apps installed via MSI or NSIS in `perMachine` and `both` mode require admin permissions for write access in `$RESOURCES` folder" }
|
windows = { level = "full", notes = "Apps installed via MSI or NSIS in `perMachine` and `both` mode require admin permissions for write access in `$RESOURCES` folder" }
|
||||||
linux = { level = "full", notes = "No write access to `$RESOURCES` folder" }
|
linux = { level = "full", notes = "No write access to `$RESOURCES` folder" }
|
||||||
@@ -20,7 +24,7 @@ ios = { level = "partial", notes = "Access is restricted to Application folder b
|
|||||||
tauri-plugin = { workspace = true, features = ["build"] }
|
tauri-plugin = { workspace = true, features = ["build"] }
|
||||||
schemars = { workspace = true }
|
schemars = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
toml = "0.9"
|
toml = "0.8"
|
||||||
tauri-utils = { workspace = true, features = ["build"] }
|
tauri-utils = { workspace = true, features = ["build"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.plugin.fs"
|
namespace = "com.plugin.fs"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
|
targetSdk = 34
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
consumerProguardFiles("consumer-rules.pro")
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -739,7 +739,7 @@ interface ReadFileOptions {
|
|||||||
async function readFile(
|
async function readFile(
|
||||||
path: string | URL,
|
path: string | URL,
|
||||||
options?: ReadFileOptions
|
options?: ReadFileOptions
|
||||||
): Promise<Uint8Array<ArrayBuffer>> {
|
): Promise<Uint8Array> {
|
||||||
if (path instanceof URL && path.protocol !== 'file:') {
|
if (path instanceof URL && path.protocol !== 'file:') {
|
||||||
throw new TypeError('Must be a file URL.')
|
throw new TypeError('Must be a file URL.')
|
||||||
}
|
}
|
||||||
@@ -838,9 +838,7 @@ async function readTextFileLines(
|
|||||||
return { value: null, done }
|
return { value: null, done }
|
||||||
}
|
}
|
||||||
|
|
||||||
const line = new TextDecoder().decode(
|
const line = new TextDecoder().decode(bytes.slice(0, bytes.byteLength))
|
||||||
bytes.slice(0, bytes.byteLength - 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: line,
|
value: line,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-fs",
|
"name": "@tauri-apps/plugin-fs",
|
||||||
"version": "2.4.5",
|
"version": "2.4.1",
|
||||||
"description": "Access the file system.",
|
"description": "Access the file system.",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -25,6 +25,6 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.8.0"
|
"@tauri-apps/api": "^2.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3748,28 +3748,6 @@ This enables all index or metadata related commands without any pre-configured a
|
|||||||
|
|
||||||
An empty permission you can use to modify the global scope.
|
An empty permission you can use to modify the global scope.
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"identifier": "read-documents",
|
|
||||||
"windows": ["main"],
|
|
||||||
"permissions": [
|
|
||||||
"fs:allow-read",
|
|
||||||
{
|
|
||||||
"identifier": "fs:scope",
|
|
||||||
"allow": [
|
|
||||||
"$APPDATA/documents/**/*"
|
|
||||||
],
|
|
||||||
"deny": [
|
|
||||||
"$APPDATA/documents/secret.txt"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
@@ -2005,10 +2005,10 @@
|
|||||||
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
"markdownDescription": "This enables all index or metadata related commands without any pre-configured accessible paths."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n",
|
"description": "An empty permission you can use to modify the global scope.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "scope",
|
"const": "scope",
|
||||||
"markdownDescription": "An empty permission you can use to modify the global scope.\n\n## Example\n\n```json\n{\n \"identifier\": \"read-documents\",\n \"windows\": [\"main\"],\n \"permissions\": [\n \"fs:allow-read\",\n {\n \"identifier\": \"fs:scope\",\n \"allow\": [\n \"$APPDATA/documents/**/*\"\n ],\n \"deny\": [\n \"$APPDATA/documents/secret.txt\"\n ]\n }\n ]\n}\n```\n"
|
"markdownDescription": "An empty permission you can use to modify the global scope."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This enables all write related commands without any pre-configured accessible paths.",
|
"description": "This enables all write related commands without any pre-configured accessible paths.",
|
||||||
|
|||||||
@@ -2,27 +2,4 @@
|
|||||||
|
|
||||||
[[permission]]
|
[[permission]]
|
||||||
identifier = "scope"
|
identifier = "scope"
|
||||||
description = """
|
description = "An empty permission you can use to modify the global scope."
|
||||||
An empty permission you can use to modify the global scope.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"identifier": "read-documents",
|
|
||||||
"windows": ["main"],
|
|
||||||
"permissions": [
|
|
||||||
"fs:allow-read",
|
|
||||||
{
|
|
||||||
"identifier": "fs:scope",
|
|
||||||
"allow": [
|
|
||||||
"$APPDATA/documents/**/*"
|
|
||||||
],
|
|
||||||
"deny": [
|
|
||||||
"$APPDATA/documents/secret.txt"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
|
|||||||
+18
-110
@@ -85,7 +85,6 @@ pub fn create<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<ResourceId> {
|
) -> CommandResult<ResourceId> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"create",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -120,7 +119,6 @@ pub fn open<R: Runtime>(
|
|||||||
options: Option<OpenOptions>,
|
options: Option<OpenOptions>,
|
||||||
) -> CommandResult<ResourceId> {
|
) -> CommandResult<ResourceId> {
|
||||||
let (file, _path) = resolve_file(
|
let (file, _path) = resolve_file(
|
||||||
"open",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -169,7 +167,6 @@ pub async fn copy_file<R: Runtime>(
|
|||||||
options: Option<CopyFileOptions>,
|
options: Option<CopyFileOptions>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
let resolved_from_path = resolve_path(
|
let resolved_from_path = resolve_path(
|
||||||
"copy-file",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -177,7 +174,6 @@ pub async fn copy_file<R: Runtime>(
|
|||||||
options.as_ref().and_then(|o| o.from_path_base_dir),
|
options.as_ref().and_then(|o| o.from_path_base_dir),
|
||||||
)?;
|
)?;
|
||||||
let resolved_to_path = resolve_path(
|
let resolved_to_path = resolve_path(
|
||||||
"copy-file",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -212,7 +208,6 @@ pub fn mkdir<R: Runtime>(
|
|||||||
options: Option<MkdirOptions>,
|
options: Option<MkdirOptions>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"mkdir",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -260,7 +255,6 @@ pub async fn read_dir<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<Vec<DirEntry>> {
|
) -> CommandResult<Vec<DirEntry>> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"read-dir",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -337,8 +331,8 @@ pub async fn read<R: Runtime>(
|
|||||||
Ok(tauri::ipc::Response::new(data))
|
Ok(tauri::ipc::Response::new(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_file_inner<R: Runtime>(
|
#[tauri::command]
|
||||||
permission: &str,
|
pub async fn read_file<R: Runtime>(
|
||||||
webview: Webview<R>,
|
webview: Webview<R>,
|
||||||
global_scope: GlobalScope<Entry>,
|
global_scope: GlobalScope<Entry>,
|
||||||
command_scope: CommandScope<Entry>,
|
command_scope: CommandScope<Entry>,
|
||||||
@@ -346,7 +340,6 @@ async fn read_file_inner<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<tauri::ipc::Response> {
|
) -> CommandResult<tauri::ipc::Response> {
|
||||||
let (mut file, path) = resolve_file(
|
let (mut file, path) = resolve_file(
|
||||||
permission,
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -374,25 +367,6 @@ async fn read_file_inner<R: Runtime>(
|
|||||||
Ok(tauri::ipc::Response::new(contents))
|
Ok(tauri::ipc::Response::new(contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn read_file<R: Runtime>(
|
|
||||||
webview: Webview<R>,
|
|
||||||
global_scope: GlobalScope<Entry>,
|
|
||||||
command_scope: CommandScope<Entry>,
|
|
||||||
path: SafeFilePath,
|
|
||||||
options: Option<BaseOptions>,
|
|
||||||
) -> CommandResult<tauri::ipc::Response> {
|
|
||||||
read_file_inner(
|
|
||||||
"read-file",
|
|
||||||
webview,
|
|
||||||
global_scope,
|
|
||||||
command_scope,
|
|
||||||
path,
|
|
||||||
options,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO, remove in v3, rely on `read_file` command instead
|
// TODO, remove in v3, rely on `read_file` command instead
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn read_text_file<R: Runtime>(
|
pub async fn read_text_file<R: Runtime>(
|
||||||
@@ -402,15 +376,7 @@ pub async fn read_text_file<R: Runtime>(
|
|||||||
path: SafeFilePath,
|
path: SafeFilePath,
|
||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<tauri::ipc::Response> {
|
) -> CommandResult<tauri::ipc::Response> {
|
||||||
read_file_inner(
|
read_file(webview, global_scope, command_scope, path, options).await
|
||||||
"read-text-file",
|
|
||||||
webview,
|
|
||||||
global_scope,
|
|
||||||
command_scope,
|
|
||||||
path,
|
|
||||||
options,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -422,7 +388,6 @@ pub fn read_text_file_lines<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<ResourceId> {
|
) -> CommandResult<ResourceId> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"read-text-file-lines",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -487,7 +452,6 @@ pub fn remove<R: Runtime>(
|
|||||||
options: Option<RemoveOptions>,
|
options: Option<RemoveOptions>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"remove",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -557,7 +521,6 @@ pub fn rename<R: Runtime>(
|
|||||||
options: Option<RenameOptions>,
|
options: Option<RenameOptions>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
let resolved_old_path = resolve_path(
|
let resolved_old_path = resolve_path(
|
||||||
"rename",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -565,7 +528,6 @@ pub fn rename<R: Runtime>(
|
|||||||
options.as_ref().and_then(|o| o.old_path_base_dir),
|
options.as_ref().and_then(|o| o.old_path_base_dir),
|
||||||
)?;
|
)?;
|
||||||
let resolved_new_path = resolve_path(
|
let resolved_new_path = resolve_path(
|
||||||
"rename",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -613,7 +575,6 @@ pub async fn seek<R: Runtime>(
|
|||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||||
permission: &str,
|
|
||||||
metadata_fn: F,
|
metadata_fn: F,
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
@@ -624,7 +585,6 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
|||||||
match path {
|
match path {
|
||||||
SafeFilePath::Url(url) => {
|
SafeFilePath::Url(url) => {
|
||||||
let (file, path) = resolve_file(
|
let (file, path) = resolve_file(
|
||||||
permission,
|
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
command_scope,
|
command_scope,
|
||||||
@@ -646,7 +606,6 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
SafeFilePath::Path(p) => get_fs_metadata(
|
SafeFilePath::Path(p) => get_fs_metadata(
|
||||||
permission,
|
|
||||||
metadata_fn,
|
metadata_fn,
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
@@ -659,7 +618,6 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
|||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||||
permission: &str,
|
|
||||||
metadata_fn: F,
|
metadata_fn: F,
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
@@ -668,7 +626,6 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<std::fs::Metadata> {
|
) -> CommandResult<std::fs::Metadata> {
|
||||||
get_fs_metadata(
|
get_fs_metadata(
|
||||||
permission,
|
|
||||||
metadata_fn,
|
metadata_fn,
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
@@ -679,7 +636,6 @@ fn get_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Meta
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_fs_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
fn get_fs_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::Metadata>>(
|
||||||
permission: &str,
|
|
||||||
metadata_fn: F,
|
metadata_fn: F,
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
@@ -688,7 +644,6 @@ fn get_fs_metadata<R: Runtime, F: FnOnce(&PathBuf) -> std::io::Result<std::fs::M
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<std::fs::Metadata> {
|
) -> CommandResult<std::fs::Metadata> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
permission,
|
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
command_scope,
|
command_scope,
|
||||||
@@ -713,7 +668,6 @@ pub fn stat<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<FileInfo> {
|
) -> CommandResult<FileInfo> {
|
||||||
let metadata = get_metadata(
|
let metadata = get_metadata(
|
||||||
"stat",
|
|
||||||
|p| std::fs::metadata(p),
|
|p| std::fs::metadata(p),
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
@@ -734,7 +688,6 @@ pub fn lstat<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<FileInfo> {
|
) -> CommandResult<FileInfo> {
|
||||||
let metadata = get_metadata(
|
let metadata = get_metadata(
|
||||||
"lstat",
|
|
||||||
|p| std::fs::symlink_metadata(p),
|
|p| std::fs::symlink_metadata(p),
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
@@ -763,7 +716,6 @@ pub async fn truncate<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"truncate",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -832,13 +784,23 @@ fn default_create_value() -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write_file_inner<R: Runtime>(
|
#[tauri::command]
|
||||||
permission: &str,
|
pub async fn write_file<R: Runtime>(
|
||||||
webview: Webview<R>,
|
webview: Webview<R>,
|
||||||
global_scope: GlobalScope<Entry>,
|
global_scope: GlobalScope<Entry>,
|
||||||
command_scope: CommandScope<Entry>,
|
command_scope: CommandScope<Entry>,
|
||||||
request: tauri::ipc::Request<'_>,
|
request: tauri::ipc::Request<'_>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
|
let data = match request.body() {
|
||||||
|
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
|
||||||
|
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
|
||||||
|
data.iter()
|
||||||
|
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
|
||||||
|
};
|
||||||
|
|
||||||
let path = request
|
let path = request
|
||||||
.headers()
|
.headers()
|
||||||
.get("path")
|
.get("path")
|
||||||
@@ -849,7 +811,6 @@ async fn write_file_inner<R: Runtime>(
|
|||||||
.map_err(|_| anyhow::anyhow!("path is not a valid UTF-8").into())
|
.map_err(|_| anyhow::anyhow!("path is not a valid UTF-8").into())
|
||||||
})
|
})
|
||||||
.and_then(|p| SafeFilePath::from_str(&p).map_err(CommandError::from))?;
|
.and_then(|p| SafeFilePath::from_str(&p).map_err(CommandError::from))?;
|
||||||
|
|
||||||
let options: Option<WriteFileOptions> = request
|
let options: Option<WriteFileOptions> = request
|
||||||
.headers()
|
.headers()
|
||||||
.get("options")
|
.get("options")
|
||||||
@@ -857,7 +818,6 @@ async fn write_file_inner<R: Runtime>(
|
|||||||
.and_then(|opts| serde_json::from_str(opts).ok());
|
.and_then(|opts| serde_json::from_str(opts).ok());
|
||||||
|
|
||||||
let (mut file, path) = resolve_file(
|
let (mut file, path) = resolve_file(
|
||||||
permission,
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -893,16 +853,6 @@ async fn write_file_inner<R: Runtime>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let data = match request.body() {
|
|
||||||
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
|
|
||||||
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
|
|
||||||
data.iter()
|
|
||||||
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
file.write_all(&data)
|
file.write_all(&data)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
@@ -913,16 +863,6 @@ async fn write_file_inner<R: Runtime>(
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn write_file<R: Runtime>(
|
|
||||||
webview: Webview<R>,
|
|
||||||
global_scope: GlobalScope<Entry>,
|
|
||||||
command_scope: CommandScope<Entry>,
|
|
||||||
request: tauri::ipc::Request<'_>,
|
|
||||||
) -> CommandResult<()> {
|
|
||||||
write_file_inner("write-file", webview, global_scope, command_scope, request).await
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO, remove in v3, rely on `write_file` command instead
|
// TODO, remove in v3, rely on `write_file` command instead
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn write_text_file<R: Runtime>(
|
pub async fn write_text_file<R: Runtime>(
|
||||||
@@ -931,14 +871,7 @@ pub async fn write_text_file<R: Runtime>(
|
|||||||
command_scope: CommandScope<Entry>,
|
command_scope: CommandScope<Entry>,
|
||||||
request: tauri::ipc::Request<'_>,
|
request: tauri::ipc::Request<'_>,
|
||||||
) -> CommandResult<()> {
|
) -> CommandResult<()> {
|
||||||
write_file_inner(
|
write_file(webview, global_scope, command_scope, request).await
|
||||||
"write-text-file",
|
|
||||||
webview,
|
|
||||||
global_scope,
|
|
||||||
command_scope,
|
|
||||||
request,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -950,7 +883,6 @@ pub fn exists<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<bool> {
|
) -> CommandResult<bool> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"exists",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -969,7 +901,6 @@ pub async fn size<R: Runtime>(
|
|||||||
options: Option<BaseOptions>,
|
options: Option<BaseOptions>,
|
||||||
) -> CommandResult<u64> {
|
) -> CommandResult<u64> {
|
||||||
let resolved_path = resolve_path(
|
let resolved_path = resolve_path(
|
||||||
"size",
|
|
||||||
&webview,
|
&webview,
|
||||||
&global_scope,
|
&global_scope,
|
||||||
&command_scope,
|
&command_scope,
|
||||||
@@ -1012,25 +943,16 @@ fn get_dir_size(path: &PathBuf) -> CommandResult<u64> {
|
|||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
pub fn resolve_file<R: Runtime>(
|
pub fn resolve_file<R: Runtime>(
|
||||||
permission: &str,
|
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
command_scope: &CommandScope<Entry>,
|
command_scope: &CommandScope<Entry>,
|
||||||
path: SafeFilePath,
|
path: SafeFilePath,
|
||||||
open_options: OpenOptions,
|
open_options: OpenOptions,
|
||||||
) -> CommandResult<(File, PathBuf)> {
|
) -> CommandResult<(File, PathBuf)> {
|
||||||
resolve_file_in_fs(
|
resolve_file_in_fs(webview, global_scope, command_scope, path, open_options)
|
||||||
permission,
|
|
||||||
webview,
|
|
||||||
global_scope,
|
|
||||||
command_scope,
|
|
||||||
path,
|
|
||||||
open_options,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_file_in_fs<R: Runtime>(
|
fn resolve_file_in_fs<R: Runtime>(
|
||||||
permission: &str,
|
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
command_scope: &CommandScope<Entry>,
|
command_scope: &CommandScope<Entry>,
|
||||||
@@ -1038,7 +960,6 @@ fn resolve_file_in_fs<R: Runtime>(
|
|||||||
open_options: OpenOptions,
|
open_options: OpenOptions,
|
||||||
) -> CommandResult<(File, PathBuf)> {
|
) -> CommandResult<(File, PathBuf)> {
|
||||||
let path = resolve_path(
|
let path = resolve_path(
|
||||||
permission,
|
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
command_scope,
|
command_scope,
|
||||||
@@ -1059,7 +980,6 @@ fn resolve_file_in_fs<R: Runtime>(
|
|||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
pub fn resolve_file<R: Runtime>(
|
pub fn resolve_file<R: Runtime>(
|
||||||
permission: &str,
|
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
command_scope: &CommandScope<Entry>,
|
command_scope: &CommandScope<Entry>,
|
||||||
@@ -1077,7 +997,6 @@ pub fn resolve_file<R: Runtime>(
|
|||||||
Ok((file, path))
|
Ok((file, path))
|
||||||
}
|
}
|
||||||
SafeFilePath::Path(path) => resolve_file_in_fs(
|
SafeFilePath::Path(path) => resolve_file_in_fs(
|
||||||
permission,
|
|
||||||
webview,
|
webview,
|
||||||
global_scope,
|
global_scope,
|
||||||
command_scope,
|
command_scope,
|
||||||
@@ -1088,7 +1007,6 @@ pub fn resolve_file<R: Runtime>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_path<R: Runtime>(
|
pub fn resolve_path<R: Runtime>(
|
||||||
permission: &str,
|
|
||||||
webview: &Webview<R>,
|
webview: &Webview<R>,
|
||||||
global_scope: &GlobalScope<Entry>,
|
global_scope: &GlobalScope<Entry>,
|
||||||
command_scope: &CommandScope<Entry>,
|
command_scope: &CommandScope<Entry>,
|
||||||
@@ -1134,17 +1052,7 @@ pub fn resolve_path<R: Runtime>(
|
|||||||
if fs_scope.scope.is_allowed(&path) || scope.is_allowed(&path) {
|
if fs_scope.scope.is_allowed(&path) || scope.is_allowed(&path) {
|
||||||
Ok(path)
|
Ok(path)
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(debug_assertions))]
|
Err(CommandError::Plugin(Error::PathForbidden(path)))
|
||||||
return Err(CommandError::Plugin(Error::PathForbidden(path)));
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
Err(
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"forbidden path: {}, maybe it is not allowed on the scope for `allow-{permission}` permission in your capability file",
|
|
||||||
path.display()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ impl<R: Runtime> Fs<R> {
|
|||||||
std::fs::File::from_raw_fd(fd)
|
std::fs::File::from_raw_fd(fd)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user