Merge remote-tracking branch 'origin/v2' into feat/scanner

pull/536/head
Lucas Nogueira 2 years ago
commit b9462bd2ce
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7

@ -0,0 +1,11 @@
[advisories]
ignore = [
# time 0.1
"RUSTSEC-2020-0071",
# needs sqlx 0.7 (still in alpha)
"RUSTSEC-2022-0090",
# wry needs kuchiki on Android
"RUSTSEC-2023-0019",
# atty is only used when the `colored` feature is enabled on tauri-plugin-log
"RUSTSEC-2021-0145"
]

@ -3,12 +3,12 @@
"pkgManagers": {
"javascript": {
"version": true,
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js npm ${ pkgFile.pkg.name } ${ pkgFile.pkg.version }",
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.cjs npm ${ pkgFile.pkg.name } ${ pkgFile.pkg.version }",
"publish": ["pnpm build", "pnpm publish --access public --no-git-checks"]
},
"rust": {
"version": true,
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js cargo ${ pkgFile.pkg.package.name } ${ pkgFile.pkg.package.version }",
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.cjs cargo ${ pkgFile.pkg.package.name } ${ pkgFile.pkg.package.version }",
"publish": [
{
"command": "cargo package --no-verify",
@ -33,85 +33,130 @@
}
},
"packages": {
"api-example": {
"path": "./examples/api/src-tauri",
"manager": "rust",
"publish": false,
"dependencies": [
"app",
"log-plugin",
"cli",
"clipboard",
"dialog",
"fs",
"global-shortcut",
"http",
"notification",
"os",
"process",
"shell",
"updater",
"window"
]
},
"api-example-js": {
"path": "./examples/api",
"manager": "javascript",
"publish": false,
"dependencies": [
"app-js",
"log-js",
"cli-js",
"clipboard-js",
"dialog-js",
"fs-js",
"global-shortcut-js",
"http-js",
"notification-js",
"os-js",
"process-js",
"shell-js",
"updater-js",
"window-js"
]
},
"app": {
"path": "./plugins/app",
"manager": "rust"
},
"app-js": {
"path": "./plugins/app",
"manager": "javascript"
},
"authenticator": {
"path": "./plugins/authenticator",
"manager": "rust-disabled"
"manager": "rust"
},
"authenticator-js": {
"path": "./plugins/authenticator",
"manager": "javascript-disabled"
"manager": "javascript"
},
"autostart": {
"path": "./plugins/autostart",
"manager": "rust-disabled"
"manager": "rust"
},
"autostart-js": {
"path": "./plugins/autostart",
"manager": "javascript-disabled"
"manager": "javascript"
},
"cli": {
"path": "./plugins/cli",
"manager": "rust-disabled"
"manager": "rust"
},
"cli-js": {
"path": "./plugins/cli",
"manager": "javascript-disabled"
"manager": "javascript"
},
"clipboard": {
"path": "./plugins/clipboard",
"manager": "rust-disabled"
"clipboard-manager": {
"path": "./plugins/clipboard-manager",
"manager": "rust"
},
"clipboard-js": {
"path": "./plugins/clipboard",
"manager": "javascript-disabled"
},
"dialog": {
"path": "./plugins/dialog",
"manager": "rust-disabled"
},
"dialog-js": {
"path": "./plugins/dialog",
"manager": "javascript-disabled"
"clipboard-manager-js": {
"path": "./plugins/clipboard-manager",
"manager": "javascript"
},
"fs": {
"path": "./plugins/fs",
"manager": "rust-disabled"
"manager": "rust"
},
"fs-js": {
"path": "./plugins/fs",
"manager": "javascript-disabled"
"manager": "javascript"
},
"fs-watch": {
"path": "./plugins/fs-watch",
"manager": "rust-disabled"
"dialog": {
"path": "./plugins/dialog",
"manager": "rust",
"dependencies": ["fs"]
},
"fs-watch-js": {
"path": "./plugins/fs-watch",
"manager": "javascript-disabled"
"dialog-js": {
"path": "./plugins/dialog",
"manager": "javascript"
},
"global-shortcut": {
"path": "./plugins/global-shortcut",
"manager": "rust-disabled"
"manager": "rust"
},
"global-shortcut-js": {
"path": "./plugins/global-shortcut",
"manager": "javascript-disabled"
"manager": "javascript"
},
"http": {
"path": "./plugins/http",
"manager": "rust-disabled"
"manager": "rust",
"dependencies": ["fs"]
},
"http-js": {
"path": "./plugins/http",
"manager": "javascript-disabled"
"manager": "javascript"
},
"localhost": {
@ -119,27 +164,37 @@
"manager": "rust"
},
"log": {
"log-plugin": {
"path": "./plugins/log",
"manager": "rust-disabled"
"manager": "rust"
},
"log-js": {
"path": "./plugins/log",
"manager": "javascript-disabled"
"manager": "javascript"
},
"notification": {
"path": "./plugins/notification",
"manager": "rust-disabled"
"manager": "rust"
},
"notification-js": {
"path": "./plugins/notification",
"manager": "javascript-disabled"
"manager": "javascript"
},
"os": {
"path": "./plugins/os",
"manager": "rust"
},
"os-js": {
"path": "./plugins/os",
"manager": "javascript"
},
"persisted-scope": {
"path": "./plugins/persisted-scope",
"manager": "rust"
"manager": "rust",
"dependencies": ["fs"]
},
"positioner": {
@ -148,66 +203,114 @@
},
"positioner-js": {
"path": "./plugins/positioner",
"manager": "javascript-disabled"
"manager": "javascript"
},
"process": {
"path": "./plugins/process",
"manager": "rust"
},
"process-js": {
"path": "./plugins/process",
"manager": "javascript"
},
"shell": {
"path": "./plugins/shell",
"manager": "rust-disabled"
"manager": "rust"
},
"shell-js": {
"path": "./plugins/shell",
"manager": "javascript-disabled"
"manager": "javascript"
},
"single-instance": {
"path": "./plugins/single-instance",
"manager": "rust-disabled"
"manager": "rust"
},
"sql": {
"path": "./plugins/sql",
"manager": "rust-disabled"
"manager": "rust",
"publish": [
{
"command": "cargo package --no-verify",
"dryRunCommand": true
},
{
"command": "echo '<details>\n<summary><em><h4>Cargo Publish</h4></em></summary>\n\n```'",
"dryRunCommand": true,
"pipe": true
},
{
"command": "cargo publish --features sqlite",
"dryRunCommand": "cargo publish --features sqlite --dry-run",
"pipe": true
},
{
"command": "echo '```\n\n</details>\n'",
"dryRunCommand": true,
"pipe": true
}
]
},
"sql-js": {
"path": "./plugins/sql",
"manager": "javascript-disabled"
"manager": "javascript"
},
"store": {
"path": "./plugins/store",
"manager": "rust-disabled"
"manager": "rust"
},
"store-js": {
"path": "./plugins/store",
"manager": "javascript-disabled"
"manager": "javascript"
},
"stronghold": {
"path": "./plugins/stronghold",
"manager": "rust-disabled"
"manager": "rust"
},
"stronghold-js": {
"path": "./plugins/stronghold",
"manager": "javascript-disabled"
"manager": "javascript"
},
"updater": {
"path": "./plugins/updater",
"manager": "rust"
},
"updater-js": {
"path": "./plugins/updater",
"manager": "javascript"
},
"upload": {
"path": "./plugins/upload",
"manager": "rust-disabled"
"manager": "rust"
},
"upload-js": {
"path": "./plugins/upload",
"manager": "javascript-disabled"
"manager": "javascript"
},
"websocket": {
"path": "./plugins/websocket",
"manager": "rust-disabled"
"manager": "rust"
},
"websocket-js": {
"path": "./plugins/websocket",
"manager": "javascript-disabled"
"manager": "javascript"
},
"window": {
"path": "./plugins/window",
"manager": "rust"
},
"window-js": {
"path": "./plugins/window",
"manager": "javascript"
},
"window-state": {
@ -216,7 +319,7 @@
},
"window-state-js": {
"path": "./plugins/window-state",
"manager": "javascript-disabled"
"manager": "javascript"
}
}
}

@ -0,0 +1,5 @@
---
"notification": patch
---
Use `window.__TAURI_INVOKE__` instead of `window.__TAURI__` in init.js, fixes usage in apps without `withGlobalTauri` enabled.

@ -0,0 +1,5 @@
---
"notification": patch
---
Play a default sound when showing a notification on Windows.

@ -0,0 +1,11 @@
---
"os": minor
"os-js": minor
---
The os plugin is recieving a few changes to improve consistency and add new features:
- Renamed `Kind` enum to `OsType` and `kind()` function to `os_type()`.
- Added `family()`,`exe_extension()`, and `hostname()` functions and their equivalents for JS.
- Removed `tempdir()` function and its equivalent on JS, use `std::env::temp_dir` instead of `temp_dir` from `tauri::path::PathResolver::temp_dir` and `path.tempDir` on JS.
- Modified `platform()` implementation to return `windows` instead of `win32` and `macos` instead of `darwin` to align with Rust's `std::env::consts::OS`

@ -1,5 +0,0 @@
---
persisted-scope: patch
---
Recursively unescape saved patterns before allowing/forbidding them. This effectively prevents `.persisted-scope` files from blowing up, which caused Out-Of-Memory issues, while automatically fixing existing broken files seamlessly.

@ -0,0 +1,9 @@
{
"tag": "alpha",
"changes": [
".changes/notification-init-script.md",
".changes/notification-sound.md",
".changes/stronghold-constructor.md",
".changes/v2-alpha.md"
]
}

@ -0,0 +1,5 @@
---
"stronghold-js": minor
---
Added `Stronghold.load` and removed its constructor.

@ -0,0 +1,53 @@
---
"app": major
"app-js": major
"authenticator": major
"authenticator-js": major
"autostart": major
"autostart-js": major
"cli": major
"cli-js": major
"clipboard-manager": major
"clipboard-manager-js": major
"dialog": major
"dialog-js": major
"fs": major
"fs-js": major
"global-shortcut": major
"global-shortcut-js": major
"http": major
"http-js": major
"localhost": major
"log-plugin": major
"log-js": major
"notification": major
"notification-js": major
"os": major
"os-js": major
"persisted-scope": major
"positioner": major
"positioner-js": major
"process": major
"process-js": major
"shell": major
"shell-js": major
"single-instance": major
"sql": major
"sql-js": major
"store": major
"store-js": major
"stronghold": major
"stronghold-js": major
"updater": major
"updater-js": major
"upload": major
"upload-js": major
"websocket": major
"websocket-js": major
"window": major
"window-js": major
"window-state": major
"window-state-js": major
---
First v2 alpha release!

@ -0,0 +1,5 @@
---
"window-state": "patch"
---
Correctly set decoration state if no saved state xists

@ -0,0 +1,5 @@
---
"window-state-js": "patch"
---
Correctly propagate the promise inside `saveWindowState`, `restoreState` and `restoreStateCurrent` so callers can choose to `await` them.

@ -2,3 +2,4 @@ target
node_modules
dist
dist-js
api-iife.js

@ -1,4 +1,7 @@
#!/bin/bash
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
## Environment used by this script:
#

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Audit JavaScript
on:

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Audit Rust
on:

@ -0,0 +1,155 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check generated files
on:
pull_request:
paths:
- ".github/workflows/check-generated-files.yml"
- "**/guest-js/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
app:
- .github/workflows/check-generated-files.yml
- plugins/app/guest-js/**
- plugins/app/src/api-iife.js
authenticator:
- .github/workflows/check-generated-files.yml
- plugins/authenticator/guest-js/**
- plugins/authenticator/src/api-iife.js
autostart:
- .github/workflows/check-generated-files.yml
- plugins/autostart/guest-js/**
- plugins/autostart/src/api-iife.js
cli:
- .github/workflows/check-generated-files.yml
- plugins/cli/guest-js/**
- plugins/cli/src/api-iife.js
clipboard-manager:
- .github/workflows/check-generated-files.yml
- plugins/clipboard-manager/guest-js/**
- plugins/clipboard-manager/src/api-iife.js
dialog:
- .github/workflows/check-generated-files.yml
- plugins/dialog/guest-js/**
- plugins/dialog/src/api-iife.js
fs:
- .github/workflows/check-generated-files.yml
- plugins/fs/guest-js/**
- plugins/fs/src/api-iife.js
global-shortcut:
- .github/workflows/check-generated-files.yml
- plugins/global-shortcut/guest-js/**
- plugins/global-shortcut/src/api-iife.js
http:
- .github/workflows/check-generated-files.yml
- plugins/http/guest-js/**
- plugins/http/src/api-iife.js
log:
- .github/workflows/check-generated-files.yml
- plugins/log/guest-js/**
- plugins/log/src/api-iife.js
notification:
- .github/workflows/check-generated-files.yml
- plugins/notification/guest-js/**
- plugins/notification/src/api-iife.js
os:
- .github/workflows/check-generated-files.yml
- plugins/os/guest-js/**
- plugins/os/src/api-iife.js
positioner:
- .github/workflows/check-generated-files.yml
- plugins/positioner/guest-js/**
- plugins/positioner/src/api-iife.js
process:
- .github/workflows/check-generated-files.yml
- plugins/process/guest-js/**
- plugins/process/src/api-iife.js
shell:
- .github/workflows/check-generated-files.yml
- plugins/shell/guest-js/**
- plugins/shell/src/api-iife.js
sql:
- .github/workflows/check-generated-files.yml
- plugins/sql/guest-js/**
- plugins/sql/src/api-iife.js
store:
- .github/workflows/check-generated-files.yml
- plugins/store/guest-js/**
- plugins/store/src/api-iife.js
stronghold:
- .github/workflows/check-generated-files.yml
- plugins/stronghold/guest-js/**
- plugins/stronghold/src/api-iife.js
updater:
- .github/workflows/check-generated-files.yml
- plugins/updater/guest-js/**
- plugins/updater/src/api-iife.js
upload:
- .github/workflows/check-generated-files.yml
- plugins/upload/guest-js/**
- plugins/upload/src/api-iife.js
websocket:
- .github/workflows/check-generated-files.yml
- plugins/websocket/guest-js/**
- plugins/websocket/src/api-iife.js
window:
- .github/workflows/check-generated-files.yml
- plugins/window/guest-js/**
- plugins/window/src/api-iife.js
window-state:
- .github/workflows/check-generated-files.yml
- plugins/window-state/guest-js/**
- plugins/window-state/src/api-iife.js
test:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache pnpm modules
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: pnpm/action-setup@v2
with:
version: 7.x.x
run_install: true
- name: build api
working-directory: plugins/${{ matrix.package }}
run: pnpm install && pnpm build
- name: check diff
run: |
./.scripts/ci/has-diff.sh

@ -0,0 +1,28 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check license header
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dorny/paths-filter@v2
id: filter
with:
list-files: shell
filters: |
added:
- added: '**'
- name: check header license on new files
if: ${{ steps.filter.outputs.added == 'true' }}
run: node .scripts/ci/check-license-header.js ${{ steps.filter.outputs.added_files }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: covector status
on: [pull_request]
@ -10,7 +14,7 @@ jobs:
with:
fetch-depth: 0 # required for use of git history
- name: covector status
uses: jbolda/covector/packages/action@covector-v0.8
uses: jbolda/covector/packages/action@covector-v0
id: covector
with:
command: "status"

@ -0,0 +1,68 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: version or publish
on:
push:
branches:
- v2
jobs:
version-or-publish:
runs-on: ubuntu-latest
timeout-minutes: 65
outputs:
change: ${{ steps.covector.outputs.change }}
commandRan: ${{ steps.covector.outputs.commandRan }}
successfulPublish: ${{ steps.covector.outputs.successfulPublish }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # required for use of git history
- uses: actions/setup-node@v3
with:
node-version: "lts/*"
registry-url: "https://registry.npmjs.org"
- uses: pnpm/action-setup@v2
with:
version: 7.x.x
run_install: true
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: cargo login
run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }}
- name: git config
run: |
git config --global user.name "${{ github.event.pusher.name }}"
git config --global user.email "${{ github.event.pusher.email }}"
- name: covector version or publish (publish when no change files present)
uses: jbolda/covector/packages/action@covector-v0
id: covector
env:
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: "version-or-publish"
createRelease: true
- name: Create Pull Request With Versions Bumped
id: cpr
uses: tauri-apps/create-pull-request@v3
if: steps.covector.outputs.commandRan == 'version'
with:
title: "Publish New Versions (v2)"
commit-message: "publish new versions"
labels: "version updates"
branch: "release-v2"
body: ${{ steps.covector.outputs.change }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: version or publish
on:
@ -29,6 +33,11 @@ jobs:
version: 7.x.x
run_install: true
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: cargo login
run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }}
@ -38,7 +47,7 @@ jobs:
git config --global user.email "${{ github.event.pusher.email }}"
- name: covector version or publish (publish when no change files present)
uses: jbolda/covector/packages/action@covector-v0.8
uses: jbolda/covector/packages/action@covector-v0
id: covector
env:
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Lint JavaScript
on:

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Lint Rust
on:
@ -8,6 +12,7 @@ on:
paths:
- ".github/workflows/lint-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
pull_request:
branches:
@ -16,6 +21,7 @@ on:
paths:
- ".github/workflows/lint-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
concurrency:
@ -23,10 +29,108 @@ concurrency:
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
tauri-plugin-app:
- .github/workflows/lint-rust.yml
- plugins/app/**
tauri-plugin-authenticator:
- .github/workflows/lint-rust.yml
- plugins/authenticator/**
tauri-plugin-autostart:
- .github/workflows/lint-rust.yml
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/lint-rust.yml
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/lint-rust.yml
- plugins/clipboard-manager/**
tauri-plugin-dialog:
- .github/workflows/lint-rust.yml
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/lint-rust.yml
- plugins/fs/**
tauri-plugin-global-shortcut:
- .github/workflows/lint-rust.yml
- plugins/global-shortcut/**
tauri-plugin-http:
- .github/workflows/lint-rust.yml
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/lint-rust.yml
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/lint-rust.yml
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/lint-rust.yml
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/lint-rust.yml
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/lint-rust.yml
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/lint-rust.yml
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/lint-rust.yml
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/lint-rust.yml
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/lint-rust.yml
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/lint-rust.yml
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/lint-rust.yml
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/lint-rust.yml
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/lint-rust.yml
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/lint-rust.yml
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/lint-rust.yml
- plugins/websocket/**
tauri-plugin-window:
- .github/workflows/lint-rust.yml
- plugins/window/**
tauri-plugin-window-state:
- .github/workflows/lint-rust.yml
- plugins/window-state/**
clippy:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
steps:
- uses: actions/checkout@v3
@ -43,17 +147,25 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: clippy
run: cargo clippy --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features -- -D warnings
- name: create dummy dist
working-directory: examples/api
run: mkdir dist
- name: clippy ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
- name: clippy sql:sqlite
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features sqlite -- -D warnings
- name: clippy ${{ matrix.package }} --all-features
if: ${{ !contains(fromJSON('["tauri-plugin-http", "tauri-plugin-upload", "tauri-plugin-updater", "tauri-plugin-websocket", "tauri-plugin-sql"]'), matrix.package) }}
run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
- name: clippy sql:mysql
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features mysql -- -D warnings
- name: clippy ${{ matrix.package }} mysql
if: matrix.package == 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features mysql -- -D warnings
- name: clippy sql:postgres
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features postgres -- -D warnings
- name: clippy ${{ matrix.package }} postgres
if: matrix.package == 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features postgres -- -D warnings
fmt:
runs-on: ubuntu-latest

@ -1,55 +0,0 @@
name: Check MSRV
on:
push:
branches:
- v1
- v2
paths:
- ".github/workflows/msrv-check.yml"
- "plugins/*/src/**"
- "**/Cargo.toml"
- "**/Cargo.lock"
pull_request:
branches:
- v1
- v2
paths:
- ".github/workflows/msrv-check.yml"
- "plugins/*/src/**"
- "**/Cargo.toml"
- "**/Cargo.lock"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
msrv:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- uses: dtolnay/rust-toolchain@1.64.0
- uses: Swatinem/rust-cache@v2
- name: build
run: cargo build --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features
- name: build sql:sqlite
run: cargo build --package 'tauri-plugin-sql' --all-targets --features sqlite
- name: build sql:mysql
run: cargo build --package 'tauri-plugin-sql' --all-targets --features mysql
- name: build sql:postgres
run: cargo build --package 'tauri-plugin-sql' --all-targets --features postgres

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Sync
on:

@ -0,0 +1,226 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Test Rust
on:
push:
branches:
- v1
- v2
paths:
- ".github/workflows/test-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
- "**/Cargo.lock"
pull_request:
branches:
- v1
- v2
paths:
- ".github/workflows/test-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
- "**/Cargo.lock"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
tauri-plugin-app:
- .github/workflows/test-rust.yml
- plugins/app/**
tauri-plugin-authenticator:
- .github/workflows/test-rust.yml
- plugins/authenticator/**
tauri-plugin-autostart:
- .github/workflows/test-rust.yml
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/test-rust.yml
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/test-rust.yml
- plugins/clipboard-manager/**
tauri-plugin-dialog:
- .github/workflows/test-rust.yml
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/test-rust.yml
- plugins/fs/**
tauri-plugin-global-shortcut:
- .github/workflows/test-rust.yml
- plugins/global-shortcut/**
tauri-plugin-http:
- .github/workflows/test-rust.yml
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/test-rust.yml
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/test-rust.yml
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/test-rust.yml
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/test-rust.yml
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/test-rust.yml
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/test-rust.yml
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/test-rust.yml
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/test-rust.yml
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/test-rust.yml
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/test-rust.yml
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/test-rust.yml
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/test-rust.yml
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/test-rust.yml
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/test-rust.yml
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/test-rust.yml
- plugins/websocket/**
tauri-plugin-window:
- .github/workflows/test-rust.yml
- plugins/window/**
tauri-plugin-window-state:
- .github/workflows/test-rust.yml
- plugins/window-state/**
test:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
platform:
- {
target: x86_64-pc-windows-msvc,
os: windows-latest,
cross: false,
command: "test",
}
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-latest,
cross: false,
command: "test",
}
- {
target: x86_64-apple-darwin,
os: macos-latest,
cross: false,
command: "test",
}
- {
target: aarch64-apple-ios,
os: macos-latest,
cross: false,
command: "build",
}
- {
target: aarch64-linux-android,
os: ubuntu-latest,
cross: true,
command: "build",
}
runs-on: ${{ matrix.platform.os }}
steps:
- uses: actions/checkout@v3
- name: install webkit2gtk and libudev for [authenticator]
if: contains(matrix.platform.target, 'unknown-linux')
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: install openssl
if: ${{ matrix.platform.os == 'windows-latest' && matrix.package == 'tauri-plugin-authenticator' }}
run: |
echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
vcpkg install openssl:x64-windows-static-md
- uses: dtolnay/rust-toolchain@1.65.0
with:
targets: ${{ matrix.platform.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.package }}
- name: create dummy dist
working-directory: examples/api
run: mkdir dist
- name: test ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
- name: test ${{ matrix.package }} --all-features
if: ${{ !contains(fromJSON('["tauri-plugin-http", "tauri-plugin-upload", "tauri-plugin-updater", "tauri-plugin-websocket", "tauri-plugin-sql"]'), matrix.package) }}
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
- name: test ${{ matrix.package }} mysql
if: matrix.package == 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features mysql
- name: test ${{ matrix.package }} postgres
if: matrix.package == 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features postgres

@ -0,0 +1 @@
auto-install-peers=true

@ -1,5 +1,8 @@
target
node_modules
dist
dist-js
pnpm-lock.yaml
Cargo.lock
Cargo.lock
.build
api-iife.js

@ -0,0 +1,121 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import fs from "fs";
import path from "path";
import readline from "readline";
const header = `Copyright 2019-2023 Tauri Programme within The Commons Conservancy
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: MIT`;
const ignoredLicense = "// Copyright 2021 Jonas Kruckenberg";
const extensions = [".rs", ".js", ".ts", ".yml", ".swift", ".kt"];
const ignore = [
"target",
"templates",
"node_modules",
"gen",
"dist",
"dist-js",
".svelte-kit",
"api-iife.js",
];
async function checkFile(file) {
if (
extensions.some((e) => file.endsWith(e)) &&
!ignore.some((i) => file.endsWith(i))
) {
const fileStream = fs.createReadStream(file);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
let contents = ``;
let i = 0;
for await (let line of rl) {
// ignore empty lines, allow shebang, swift-tools-version and bundler license
if (
line.length === 0 ||
line.startsWith("#!") ||
line.startsWith("// swift-tools-version:") ||
line === ignoredLicense
) {
continue;
}
// strip comment marker
if (line.startsWith("// ")) {
line = line.substring(3);
} else if (line.startsWith("# ")) {
line = line.substring(2);
}
contents += line;
if (++i === 3) {
break;
}
contents += "\n";
}
if (contents !== header) {
return true;
}
}
return false;
}
async function check(src) {
const missingHeader = [];
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
const p = path.join(src, entry.name);
if (entry.isSymbolicLink() || ignore.includes(entry.name)) {
continue;
}
if (entry.isDirectory()) {
const missing = await check(p);
missingHeader.push(...missing);
} else {
const isMissing = await checkFile(p);
if (isMissing) {
missingHeader.push(p);
}
}
}
return missingHeader;
}
const [_bin, _script, ...files] = process.argv;
if (files.length > 0) {
async function run() {
const missing = [];
for (const f of files) {
const isMissing = await checkFile(f);
if (isMissing) {
missing.push(f);
}
}
if (missing.length > 0) {
console.log(missing.join("\n"));
process.exit(1);
}
}
run();
} else {
check(path.resolve(new URL(import.meta.url).pathname, "../../..")).then(
(missing) => {
if (missing.length > 0) {
console.log(missing.join("\n"));
process.exit(1);
}
}
);
}

@ -0,0 +1,9 @@
#!/bin/bash
if git diff --quiet --ignore-submodules HEAD
then
echo "working directory is clean"
else
echo "found diff"
exit 1
fi

@ -44,10 +44,14 @@ https.get(url, options, (response) => {
response.on("end", function () {
const data = JSON.parse(chunks.join(""));
if (kind === "cargo") {
const versions = data.versions.filter((v) => v.num.startsWith(target));
console.log(versions.length ? versions[0].num : "0.0.0");
if (data.versions) {
const versions = data.versions.filter((v) => v.num.startsWith(target));
console.log(versions.length ? versions[0].num : "0.0.0");
} else {
console.log("0.0.0");
}
} else if (kind === "npm") {
const versions = Object.keys(data.versions).filter((v) =>
const versions = Object.keys(data.versions || {}).filter((v) =>
v.startsWith(target)
);
console.log(versions[versions.length - 1] || "0.0.0");

726
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,13 +1,12 @@
[workspace]
members = ["plugins/*", "examples/*/src-tauri"]
exclude = ["plugins/fs", "plugins/http", "examples/api/src-tauri"]
members = ["plugins/*", "plugins/*/tests/*", "examples/*/src-tauri"]
resolver = "2"
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
log = "0.4"
tauri = "2.0.0-alpha.8"
tauri-build = "2.0.0-alpha.4"
tauri = "2.0.0-alpha.9"
tauri-build = "2.0.0-alpha.5"
serde_json = "1"
thiserror = "1"
@ -15,4 +14,12 @@ thiserror = "1"
edition = "2021"
authors = [ "Tauri Programme within The Commons Conservancy" ]
license = "Apache-2.0 OR MIT"
rust-version = "1.64"
rust-version = "1.65"
# default to small, optimized release binaries
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
incremental = false
opt-level = "s"

@ -1,21 +1,19 @@
## Plugins Found Here
| | | Win | Mac | Lin | iOS | And |
| ------------------------------------------ | --------------------------------------------------------- | --- | --- | --- | --- | --- |
| [authenticator](plugins/authenticator) | Interface with hardware security keys. | ✅ | ✅ | ✅ | ? | ? |
| [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ? | ? |
| [fs-extra](plugins/fs-extra) | File system methods that aren't included in the core API. | ✅ | ✅ | ✅ | ? | ? |
| [fs-watch](plugins/fs-watch) | Watch the filesystem for changes. | ✅ | ✅ | ✅ | ? | ? |
| [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? |
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ? | ? |
| [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ? | ✅ | ? | ? |
| [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | ? |
| [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ? | ? |
| [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? |
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? |
| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
| [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ? | ? |
| | | Win | Mac | Lin | iOS | And |
| ------------------------------------------ | ------------------------------------------------------ | --- | --- | --- | --- | --- |
| [authenticator](plugins/authenticator) | Interface with hardware security keys. | ✅ | ✅ | ✅ | ? | ? |
| [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ? | ? |
| [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? |
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ? | ? |
| [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ? | ✅ | ? | ? |
| [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | ? |
| [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ? | ? |
| [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? |
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? |
| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
| [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ? | ? |
_This repo and all plugins require a Rust version of at least **1.64**_
_This repo and all plugins require a Rust version of at least **1.65**_

@ -1,4 +1,7 @@
#!/usr/bin/env bash
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
export ICONS_VOLUME="$(realpath icons)"
export DIST_VOLUME="$(realpath dist)"

@ -0,0 +1,7 @@
# Changelog
## \[2.0.0-alpha.0]
### Dependencies
- Plugins v2 alpha.

@ -1,6 +1,7 @@
{
"name": "svelte-app",
"version": "1.0.0",
"private": true,
"version": "2.0.0-alpha.0",
"type": "module",
"scripts": {
"dev": "vite --clearScreen false",
@ -8,23 +9,28 @@
"serve": "vite preview"
},
"dependencies": {
"@tauri-apps/api": "2.0.0-alpha.3",
"@tauri-apps/cli": "2.0.0-alpha.8",
"@tauri-apps/api": "2.0.0-alpha.4",
"@zerodevx/svelte-json-view": "0.2.1",
"tauri-plugin-barcode-scanner-api": "0.0.0",
"tauri-plugin-cli-api": "0.0.0",
"tauri-plugin-clipboard-api": "0.0.0",
"tauri-plugin-dialog-api": "0.0.0",
"tauri-plugin-fs-api": "0.0.0",
"tauri-plugin-global-shortcut-api": "0.0.0",
"tauri-plugin-http-api": "0.0.0",
"tauri-plugin-notification-api": "0.0.0",
"tauri-plugin-shell-api": "0.0.0"
"@tauri-apps/plugin-app": "2.0.0-alpha.0",
"@tauri-apps/plugin-barcode-scanner": "0.0.0",
"@tauri-apps/plugin-cli": "2.0.0-alpha.0",
"@tauri-apps/plugin-clipboard-manager": "2.0.0-alpha.0",
"@tauri-apps/plugin-dialog": "2.0.0-alpha.0",
"@tauri-apps/plugin-fs": "2.0.0-alpha.0",
"@tauri-apps/plugin-global-shortcut": "2.0.0-alpha.0",
"@tauri-apps/plugin-http": "2.0.0-alpha.0",
"@tauri-apps/plugin-notification": "2.0.0-alpha.0",
"@tauri-apps/plugin-os": "2.0.0-alpha.0",
"@tauri-apps/plugin-process": "2.0.0-alpha.0",
"@tauri-apps/plugin-shell": "2.0.0-alpha.0",
"@tauri-apps/plugin-updater": "2.0.0-alpha.0",
"@tauri-apps/plugin-window": "2.0.0-alpha.0"
},
"devDependencies": {
"@iconify-json/codicon": "^1.1.10",
"@iconify-json/ph": "^1.1.1",
"@sveltejs/vite-plugin-svelte": "^1.0.1",
"@tauri-apps/cli": "2.0.0-alpha.9",
"internal-ip": "^7.0.0",
"svelte": "^3.49.0",
"unocss": "^0.39.3",

@ -0,0 +1,13 @@
# Changelog
## \[2.0.0-alpha.1]
### Dependencies
- Updated to latest `notification`
## \[2.0.0-alpha.0]
### Dependencies
- Plugins v2 alpha.

File diff suppressed because it is too large Load Diff

@ -1,49 +1,50 @@
[package]
name = "api"
version = "0.1.0"
publish = false
version = "2.0.0-alpha.1"
description = "An example Tauri Application showcasing the api"
edition = "2021"
rust-version = "1.64"
rust-version = "1.65"
license = "Apache-2.0 OR MIT"
[lib]
crate-type = ["staticlib", "cdylib", "rlib"]
crate-type = [ "staticlib", "cdylib", "rlib" ]
[build-dependencies]
tauri-build = { version = "2.0.0-alpha.4", features = ["codegen", "isolation"] }
tauri-build = { workspace = true, features = [ "codegen", "isolation" ] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { workspace = true }
serde = { workspace = true }
tiny_http = "0.11"
log = "0.4"
tauri-plugin-log = { path = "../../../plugins/log" }
tauri-plugin-fs = { path = "../../../plugins/fs" }
tauri-plugin-clipboard = { path = "../../../plugins/clipboard" }
tauri-plugin-dialog = { path = "../../../plugins/dialog" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ "http-multipart" ] }
tauri-plugin-notification = { path = "../../../plugins/notification", features = [ "windows7-compat" ] }
tauri-plugin-shell = { path = "../../../plugins/shell" }
[patch.crates-io]
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next" }
tauri-build = { git = "https://github.com/tauri-apps/tauri", branch = "next" }
[dependencies.tauri]
version = "2.0.0-alpha.8"
features = [
"api-all",
log = { workspace = true }
tauri-plugin-app = { path = "../../../plugins/app", version = "2.0.0-alpha.0" }
tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.0-alpha.0" }
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.0-alpha.0" }
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.0-alpha.0" }
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-alpha.0" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ], version = "2.0.0-alpha.0" }
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-alpha.0", features = [ "windows7-compat" ] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-alpha.0" }
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-alpha.0" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.0" }
tauri-plugin-window = { path = "../../../plugins/window", version = "2.0.0-alpha.0", features = [ "devtools", "icon-ico", "icon-png" ] }
[dependencies.tauri]
workspace = true
features = [
"icon-ico",
"icon-png",
"isolation",
"macos-private-api",
"system-tray",
"updater"
"protocol-asset"
]
[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" }
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut" }
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.0.0-alpha.0" }
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.0.0-alpha.0" }
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-alpha.0" }
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner" }
@ -53,11 +54,3 @@ window-shadows = "0.2"
[features]
custom-protocol = [ "tauri/custom-protocol" ]
# default to small, optimized release binaries
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
incremental = false
opt-level = "s"

@ -3,10 +3,10 @@
// SPDX-License-Identifier: MIT
fn main() {
let mut codegen = tauri_build::CodegenContext::new();
if !cfg!(feature = "custom-protocol") {
codegen = codegen.dev();
}
codegen.build();
tauri_build::build();
let mut codegen = tauri_build::CodegenContext::new();
if !cfg!(feature = "custom-protocol") {
codegen = codegen.dev();
}
codegen.build();
tauri_build::build();
}

@ -8,6 +8,7 @@ build
.externalNativeBuild
.cxx
local.properties
key.properties
/.tauri
/tauri.settings.gradle

@ -1,113 +0,0 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rustPlugin")
}
android {
compileSdk = 33
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
sourceSets.getByName("main") {
// Vulkan validation layers
val ndkHome = System.getenv("NDK_HOME")
jniLibs.srcDir("${ndkHome}/sources/third_party/vulkan/src/build-android/jniLibs")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packagingOptions { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
val proguards = fileTree(".") {
include("*.pro")
}
proguardFiles(*proguards.toList().toTypedArray())
}
}
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += (findProperty("abiList") as? String)?.split(",") ?: listOf( "arm64-v8a", "armeabi-v7a", "x86", "x86_64",
)
}
}
create("arm64") {
dimension = "abi"
ndk {
abiFilters += listOf("arm64-v8a")
}
}
create("arm") {
dimension = "abi"
ndk {
abiFilters += listOf("armeabi-v7a")
}
}
create("x86") {
dimension = "abi"
ndk {
abiFilters += listOf("x86")
}
}
create("x86_64") {
dimension = "abi"
ndk {
abiFilters += listOf("x86_64")
}
}
}
assetPacks += mutableSetOf()
namespace = "com.tauri.api"
}
rust {
rootDirRel = "../../../../"
targets = (findProperty("targetList") as? String)?.split(",") ?: listOf("aarch64", "armv7", "i686", "x86_64")
arches = (findProperty("archList") as? String)?.split(",") ?: listOf("arm64", "arm", "x86", "x86_64")
}
dependencies {
implementation("androidx.webkit:webkit:1.5.0")
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("com.google.android.material:material:1.7.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
implementation(project(":tauri-android"))
}
apply(from = "tauri.build.gradle.kts")
afterEvaluate {
android.applicationVariants.all {
tasks["mergeUniversalReleaseJniLibFolders"].dependsOn(tasks["rustBuildRelease"])
tasks["mergeUniversalDebugJniLibFolders"].dependsOn(tasks["rustBuildDebug"])
if (findProperty("targetList") == null) {
productFlavors.filter{ it.name != "universal" }.forEach { _ ->
val archAndBuildType = name.capitalize()
tasks["merge${archAndBuildType}JniLibFolders"].dependsOn(tasks["rustBuild${archAndBuildType}"])
}
}
}
}

@ -1,4 +0,0 @@
package com.tauri.api
class MainActivity : TauriActivity() {
}

@ -1,25 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean").configure {
delete("build")
}

@ -1,23 +0,0 @@
plugins {
`kotlin-dsl`
}
gradlePlugin {
plugins {
create("pluginsForCoolKids") {
id = "rustPlugin"
implementationClass = "com.tauri.RustPlugin"
}
}
}
repositories {
google()
mavenCentral()
}
dependencies {
compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:7.3.1")
}

@ -1,59 +0,0 @@
package com.tauri
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File
import java.util.*
const val TASK_GROUP = "rust"
open class Config {
var rootDirRel: String? = null
var targets: List<String>? = null
var arches: List<String>? = null
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) {
config = project.extensions.create("rust", Config::class.java)
project.afterEvaluate {
if (config.targets == null) {
throw GradleException("targets cannot be null")
}
if (config.arches == null) {
throw GradleException("arches cannot be null")
}
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.capitalize(Locale.ROOT)
val buildTask = project.tasks.maybeCreate(
"rustBuild$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
for (targetPair in config.targets!!.withIndex()) {
val targetName = targetPair.value
val targetArch = config.arches!![targetPair.index]
val targetArchCapitalized = targetArch.capitalize(Locale.ROOT)
val targetBuildTask = project.tasks.maybeCreate(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel?.let { File(it) }
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
project.tasks.findByName("preBuild")?.mustRunAfter(targetBuildTask)
}
}
}
}
}

@ -1,6 +0,0 @@
include ':app'
include ':tauri-android'
project(':tauri-android').projectDir = new File('./.tauri/tauri-api')
apply from: 'tauri.settings.gradle'

@ -1,4 +1,5 @@
/src/main/java/com/tauri/api/generated
/src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts
/proguard-tauri.pro

@ -0,0 +1,57 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rust")
}
android {
compileSdk = 33
namespace = "com.tauri.api"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
proguardFiles(
*fileTree(".") { include("**/*.pro") }
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
.toList().toTypedArray()
)
}
}
kotlinOptions {
jvmTarget = "1.8"
}
}
rust {
rootDirRel = "../../../"
}
dependencies {
implementation("androidx.webkit:webkit:1.6.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}
apply(from = "tauri.build.gradle.kts")

@ -14,7 +14,6 @@
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

@ -0,0 +1,3 @@
package com.tauri.api
class MainActivity : TauriActivity()

@ -1,14 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath("com.android.tools.build:gradle:8.0.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
}
}

@ -5,8 +5,8 @@ plugins {
gradlePlugin {
plugins {
create("pluginsForCoolKids") {
id = "rustPlugin"
implementationClass = "app.tauri.RustPlugin"
id = "rust"
implementationClass = "RustPlugin"
}
}
}
@ -18,6 +18,6 @@ repositories {
dependencies {
compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:7.3.1")
implementation("com.android.tools.build:gradle:8.0.0")
}

@ -1,28 +1,22 @@
package com.tauri
import java.io.File
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction
open class BuildTask : DefaultTask() {
@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
var rootDirRel: File? = null
@Input
var rootDirRel: String? = null
@Input
var target: String? = null
@Input
var release: Boolean? = null
@TaskAction
fun build() {
val executable = """yarn""";
fun assemble() {
val executable = """pnpm""";
try {
runTauriCli(executable)
} catch (e: Exception) {
@ -41,7 +35,7 @@ open class BuildTask : DefaultTask() {
val args = listOf("tauri", "android", "android-studio-script");
project.exec {
workingDir(File(project.projectDir, rootDirRel.path))
workingDir(File(project.projectDir, rootDirRel))
executable(executable)
args(args)
if (project.logger.isEnabled(LogLevel.DEBUG)) {

@ -0,0 +1,85 @@
import com.android.build.api.dsl.ApplicationExtension
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
const val TASK_GROUP = "rust"
open class Config {
lateinit var rootDirRel: String
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) = with(project) {
config = extensions.create("rust", Config::class.java)
val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64");
val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList
val defaultArchList = listOf("arm64", "arm", "x86", "x86_64");
val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList
val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64")
extensions.configure<ApplicationExtension> {
@Suppress("UnstableApiUsage")
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += abiList
}
}
defaultArchList.forEachIndexed { index, arch ->
create(arch) {
dimension = "abi"
ndk {
abiFilters.add(defaultAbiList[index])
}
}
}
}
}
afterEvaluate {
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.replaceFirstChar { it.uppercase() }
val buildTask = tasks.maybeCreate(
"rustBuildUniversal$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask)
for (targetPair in targetsList.withIndex()) {
val targetName = targetPair.value
val targetArch = archList[targetPair.index]
val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() }
val targetBuildTask = project.tasks.maybeCreate(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn(
targetBuildTask
)
}
}
}
}
}

@ -20,4 +20,6 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false

@ -1,6 +1,6 @@
#Tue May 10 19:22:52 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

@ -0,0 +1,3 @@
include ':app'
apply from: 'tauri.settings.gradle'

@ -31,12 +31,16 @@ pub fn run() {
.level(log::LevelFilter::Info)
.build(),
)
.plugin(tauri_plugin_app::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_clipboard::init())
.plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_window::init())
.setup(move |app| {
#[cfg(desktop)]
{
@ -44,6 +48,8 @@ pub fn run() {
app.handle().plugin(tauri_plugin_cli::init())?;
app.handle()
.plugin(tauri_plugin_global_shortcut::Builder::new().build())?;
app.handle()
.plugin(tauri_plugin_updater::Builder::new().build())?;
}
#[cfg(mobile)]

@ -46,6 +46,45 @@
]
}
}
},
"fs": {
"scope": {
"allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
},
"shell": {
"open": true,
"scope": [
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"http": {
"scope": ["http://localhost:3003"]
},
"updater": {
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
}
},
"tauri": {
@ -75,57 +114,10 @@
}
}
}
}
},
"updater": {
"active": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK",
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
},
"allowlist": {
"all": true,
"fs": {
"scope": {
"allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
},
"shell": {
"open": true,
"scope": [
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"protocol": {
"asset": true,
"assetScope": {
"allow": ["$APPDATA/db/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
},
"http": {
"scope": ["http://localhost:3003"]
"updater": {
"active": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK"
}
},
"windows": [],
@ -136,7 +128,14 @@
"img-src": "'self' asset: https://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com"
},
"freezePrototype": true
"freezePrototype": true,
"assetProtocol": {
"enable": true,
"scope": {
"allow": ["$APPDATA/db/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
}
},
"systemTray": {
"iconPath": "icons/tray_icon_with_transparency.png",

@ -1,191 +1,191 @@
<script>
import { writable } from 'svelte/store'
import { open } from 'tauri-plugin-shell-api'
import { appWindow, getCurrent } from '@tauri-apps/api/window'
import * as os from '@tauri-apps/api/os'
import Welcome from './views/Welcome.svelte'
import Cli from './views/Cli.svelte'
import Communication from './views/Communication.svelte'
import Dialog from './views/Dialog.svelte'
import FileSystem from './views/FileSystem.svelte'
import Http from './views/Http.svelte'
import Notifications from './views/Notifications.svelte'
import Window from './views/Window.svelte'
import Shortcuts from './views/Shortcuts.svelte'
import Shell from './views/Shell.svelte'
import Updater from './views/Updater.svelte'
import Clipboard from './views/Clipboard.svelte'
import WebRTC from './views/WebRTC.svelte'
import Scanner from './views/Scanner.svelte'
import App from './views/App.svelte'
import { onMount } from 'svelte'
import { listen } from '@tauri-apps/api/event'
import { ask } from 'tauri-plugin-dialog-api'
if (appWindow.label !== 'main') {
import { writable } from "svelte/store";
import { open } from "@tauri-apps/plugin-shell";
import { appWindow, getCurrent } from "@tauri-apps/plugin-window";
import * as os from "@tauri-apps/plugin-os";
import Welcome from "./views/Welcome.svelte";
import Cli from "./views/Cli.svelte";
import Communication from "./views/Communication.svelte";
import Dialog from "./views/Dialog.svelte";
import FileSystem from "./views/FileSystem.svelte";
import Http from "./views/Http.svelte";
import Notifications from "./views/Notifications.svelte";
import Window from "./views/Window.svelte";
import Shortcuts from "./views/Shortcuts.svelte";
import Shell from "./views/Shell.svelte";
import Updater from "./views/Updater.svelte";
import Clipboard from "./views/Clipboard.svelte";
import WebRTC from "./views/WebRTC.svelte";
import Scanner from "./views/Scanner.svelte";
import App from "./views/App.svelte";
import { onMount } from "svelte";
import { ask } from "@tauri-apps/plugin-dialog";
if (appWindow.label !== "main") {
appWindow.onCloseRequested(async (event) => {
const confirmed = await confirm('Are you sure?')
const confirmed = await confirm("Are you sure?");
if (!confirmed) {
// user did not confirm closing the window; let's prevent it
event.preventDefault()
event.preventDefault();
}
})
});
}
appWindow.onFileDropEvent((event) => {
onMessage(`File drop: ${JSON.stringify(event.payload)}`)
})
onMessage(`File drop: ${JSON.stringify(event.payload)}`);
});
const userAgent = navigator.userAgent.toLowerCase()
const isMobile = userAgent.includes('android') || userAgent.includes('iphone')
const userAgent = navigator.userAgent.toLowerCase();
const isMobile =
userAgent.includes("android") || userAgent.includes("iphone");
const views = [
{
label: 'Welcome',
label: "Welcome",
component: Welcome,
icon: 'i-ph-hand-waving'
icon: "i-ph-hand-waving",
},
{
label: 'Communication',
label: "Communication",
component: Communication,
icon: 'i-codicon-radio-tower'
icon: "i-codicon-radio-tower",
},
!isMobile && {
label: 'CLI',
label: "CLI",
component: Cli,
icon: 'i-codicon-terminal'
icon: "i-codicon-terminal",
},
!isMobile && {
label: 'Dialog',
{
label: "Dialog",
component: Dialog,
icon: 'i-codicon-multiple-windows'
icon: "i-codicon-multiple-windows",
},
{
label: 'File system',
label: "File system",
component: FileSystem,
icon: 'i-codicon-files'
icon: "i-codicon-files",
},
{
label: 'HTTP',
label: "HTTP",
component: Http,
icon: 'i-ph-globe-hemisphere-west'
icon: "i-ph-globe-hemisphere-west",
},
!isMobile && {
label: 'Notifications',
label: "Notifications",
component: Notifications,
icon: 'i-codicon-bell-dot'
icon: "i-codicon-bell-dot",
},
!isMobile && {
label: 'App',
label: "App",
component: App,
icon: 'i-codicon-hubot'
icon: "i-codicon-hubot",
},
!isMobile && {
label: 'Window',
label: "Window",
component: Window,
icon: 'i-codicon-window'
icon: "i-codicon-window",
},
!isMobile && {
label: 'Shortcuts',
label: "Shortcuts",
component: Shortcuts,
icon: 'i-codicon-record-keys'
icon: "i-codicon-record-keys",
},
{
label: 'Shell',
label: "Shell",
component: Shell,
icon: 'i-codicon-terminal-bash'
icon: "i-codicon-terminal-bash",
},
!isMobile && {
label: 'Updater',
label: "Updater",
component: Updater,
icon: 'i-codicon-cloud-download'
icon: "i-codicon-cloud-download",
},
!isMobile && {
label: 'Clipboard',
label: "Clipboard",
component: Clipboard,
icon: 'i-codicon-clippy'
icon: "i-codicon-clippy",
},
{
label: 'WebRTC',
label: "WebRTC",
component: WebRTC,
icon: 'i-ph-broadcast'
icon: "i-ph-broadcast",
},
isMobile && {
label: 'Scanner',
label: "Scanner",
component: Scanner,
icon: 'i-ph-scan'
}
]
icon: "i-ph-scan",
},
];
let selected = views[0]
let selected = views[0];
function select(view) {
selected = view
selected = view;
}
// Window controls
let isWindowMaximized
let isWindowMaximized;
onMount(async () => {
const window = getCurrent()
isWindowMaximized = await window.isMaximized()
listen('tauri://resize', async () => {
isWindowMaximized = await window.isMaximized()
})
})
const window = getCurrent();
isWindowMaximized = await window.isMaximized();
window.onResized(async () => {
isWindowMaximized = await window.isMaximized();
});
});
function minimize() {
getCurrent().minimize()
getCurrent().minimize();
}
async function toggleMaximize() {
const window = getCurrent()
;(await window.isMaximized()) ? window.unmaximize() : window.maximize()
const window = getCurrent();
(await window.isMaximized()) ? window.unmaximize() : window.maximize();
}
let confirmed_close = false
let confirmed_close = false;
async function close() {
if (!confirmed_close) {
confirmed_close = await ask(
'Are you sure that you want to close this window?',
"Are you sure that you want to close this window?",
{
title: 'Tauri API'
title: "Tauri API",
}
)
);
if (confirmed_close) {
getCurrent().close()
getCurrent().close();
}
}
}
// dark/light
let isDark
let isDark;
onMount(() => {
isDark = localStorage && localStorage.getItem('theme') == 'dark'
applyTheme(isDark)
})
isDark = localStorage && localStorage.getItem("theme") == "dark";
applyTheme(isDark);
});
function applyTheme(isDark) {
const html = document.querySelector('html')
isDark ? html.classList.add('dark') : html.classList.remove('dark')
localStorage && localStorage.setItem('theme', isDark ? 'dark' : '')
const html = document.querySelector("html");
isDark ? html.classList.add("dark") : html.classList.remove("dark");
localStorage && localStorage.setItem("theme", isDark ? "dark" : "");
}
function toggleDark() {
isDark = !isDark
applyTheme(isDark)
isDark = !isDark;
applyTheme(isDark);
}
// Console
let messages = writable([])
let messages = writable([]);
function onMessage(value) {
messages.update((r) => [
{
html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
(typeof value === 'string' ? value : JSON.stringify(value, null, 1)) +
'</pre>'
(typeof value === "string" ? value : JSON.stringify(value, null, 1)) +
"</pre>",
},
...r
])
...r,
]);
}
// this function is renders HTML without sanitizing it so it's insecure
@ -196,108 +196,110 @@
html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
html +
'</pre>'
"</pre>",
},
...r
])
...r,
]);
}
function clear() {
messages.update(() => [])
messages.update(() => []);
}
let consoleEl, consoleH, cStartY
let minConsoleHeight = 50
let consoleEl, consoleH, cStartY;
let minConsoleHeight = 50;
function startResizingConsole(e) {
cStartY = e.clientY
cStartY = e.clientY;
const styles = window.getComputedStyle(consoleEl)
consoleH = parseInt(styles.height, 10)
const styles = window.getComputedStyle(consoleEl);
consoleH = parseInt(styles.height, 10);
const moveHandler = (e) => {
const dy = e.clientY - cStartY
const newH = consoleH - dy
const dy = e.clientY - cStartY;
const newH = consoleH - dy;
consoleEl.style.height = `${
newH < minConsoleHeight ? minConsoleHeight : newH
}px`
}
}px`;
};
const upHandler = () => {
document.removeEventListener('mouseup', upHandler)
document.removeEventListener('mousemove', moveHandler)
}
document.addEventListener('mouseup', upHandler)
document.addEventListener('mousemove', moveHandler)
document.removeEventListener("mouseup", upHandler);
document.removeEventListener("mousemove", moveHandler);
};
document.addEventListener("mouseup", upHandler);
document.addEventListener("mousemove", moveHandler);
}
let isWindows
let isWindows;
onMount(async () => {
isWindows = (await os.platform()) === 'win32'
})
isWindows = (await os.platform()) === "win32";
});
// mobile
let isSideBarOpen = false
let sidebar
let sidebarToggle
let isDraggingSideBar = false
let draggingStartPosX = 0
let draggingEndPosX = 0
const clamp = (min, num, max) => Math.min(Math.max(num, min), max)
let isSideBarOpen = false;
let sidebar;
let sidebarToggle;
let isDraggingSideBar = false;
let draggingStartPosX = 0;
let draggingEndPosX = 0;
const clamp = (min, num, max) => Math.min(Math.max(num, min), max);
function toggleSidebar(sidebar, isSideBarOpen) {
sidebar.style.setProperty(
'--translate-x',
`${isSideBarOpen ? '0' : '-18.75'}rem`
)
"--translate-x",
`${isSideBarOpen ? "0" : "-18.75"}rem`
);
}
onMount(() => {
sidebar = document.querySelector('#sidebar')
sidebarToggle = document.querySelector('#sidebarToggle')
sidebar = document.querySelector("#sidebar");
sidebarToggle = document.querySelector("#sidebarToggle");
document.addEventListener('click', (e) => {
document.addEventListener("click", (e) => {
if (sidebarToggle.contains(e.target)) {
isSideBarOpen = !isSideBarOpen
isSideBarOpen = !isSideBarOpen;
} else if (isSideBarOpen && !sidebar.contains(e.target)) {
isSideBarOpen = false
isSideBarOpen = false;
}
})
});
document.addEventListener('touchstart', (e) => {
if (sidebarToggle.contains(e.target)) return
document.addEventListener("touchstart", (e) => {
if (sidebarToggle.contains(e.target)) return;
const x = e.touches[0].clientX
const x = e.touches[0].clientX;
if ((0 < x && x < 20 && !isSideBarOpen) || isSideBarOpen) {
isDraggingSideBar = true
draggingStartPosX = x
isDraggingSideBar = true;
draggingStartPosX = x;
}
})
});
document.addEventListener('touchmove', (e) => {
document.addEventListener("touchmove", (e) => {
if (isDraggingSideBar) {
const x = e.touches[0].clientX
draggingEndPosX = x
const delta = (x - draggingStartPosX) / 10
const x = e.touches[0].clientX;
draggingEndPosX = x;
const delta = (x - draggingStartPosX) / 10;
sidebar.style.setProperty(
'--translate-x',
"--translate-x",
`-${clamp(0, isSideBarOpen ? 0 - delta : 18.75 - delta, 18.75)}rem`
)
);
}
})
});
document.addEventListener('touchend', () => {
document.addEventListener("touchend", () => {
if (isDraggingSideBar) {
const delta = (draggingEndPosX - draggingStartPosX) / 10
isSideBarOpen = isSideBarOpen ? delta > -(18.75 / 2) : delta > 18.75 / 2
const delta = (draggingEndPosX - draggingStartPosX) / 10;
isSideBarOpen = isSideBarOpen
? delta > -(18.75 / 2)
: delta > 18.75 / 2;
}
isDraggingSideBar = false
})
})
isDraggingSideBar = false;
});
});
$: {
const sidebar = document.querySelector('#sidebar')
const sidebar = document.querySelector("#sidebar");
if (sidebar) {
toggleSidebar(sidebar, isSideBarOpen)
toggleSidebar(sidebar, isSideBarOpen);
}
}
</script>
@ -316,7 +318,7 @@
children:items-center children:justify-center"
>
<span
title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'}
title={isDark ? "Switch to Light mode" : "Switch to Dark mode"}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleDark}
>
@ -334,7 +336,7 @@
<div class="i-codicon-chrome-minimize" />
</span>
<span
title={isWindowMaximized ? 'Restore' : 'Maximize'}
title={isWindowMaximized ? "Restore" : "Maximize"}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleMaximize}
>
@ -346,7 +348,7 @@
</span>
<span
title="Close"
class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText "
class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
on:click={close}
>
<div class="i-codicon-chrome-close" />
@ -377,7 +379,7 @@
bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2"
>
<img
on:click={() => open('https://tauri.app/')}
on:click={() => open("https://tauri.app/")}
class="self-center p-7 cursor-pointer"
src="tauri_logo.png"
alt="Tauri logo"
@ -433,8 +435,8 @@
href="##"
class="nv {selected === view ? 'nv_selected' : ''}"
on:click={() => {
select(view)
isSideBarOpen = false
select(view);
isSideBarOpen = false;
}}
>
<div class="{view.icon} mr-2" />

@ -1,24 +1,24 @@
<script>
import { show, hide } from '@tauri-apps/api/app'
import { show, hide } from "@tauri-apps/plugin-app";
export let onMessage
export let onMessage;
function showApp() {
hideApp()
.then(() => {
setTimeout(() => {
show()
.then(() => onMessage('Shown app'))
.catch(onMessage)
}, 2000)
.then(() => onMessage("Shown app"))
.catch(onMessage);
}, 2000);
})
.catch(onMessage)
.catch(onMessage);
}
function hideApp() {
return hide()
.then(() => onMessage('Hide app'))
.catch(onMessage)
.then(() => onMessage("Hide app"))
.catch(onMessage);
}
</script>

@ -1,5 +1,5 @@
<script>
import { getMatches } from "tauri-plugin-cli-api";
import { getMatches } from "@tauri-apps/plugin-cli";
export let onMessage;

@ -1,23 +1,23 @@
<script>
import { writeText, readText } from 'tauri-plugin-clipboard-api'
import { writeText, readText } from "@tauri-apps/plugin-clipboard-manager";
export let onMessage
let text = 'clipboard message'
export let onMessage;
let text = "clipboard message";
function write() {
writeText(text)
.then(() => {
onMessage('Wrote to the clipboard')
onMessage("Wrote to the clipboard");
})
.catch(onMessage)
.catch(onMessage);
}
function read() {
readText()
.then((contents) => {
onMessage(`Clipboard contents: ${contents}`)
onMessage(`Clipboard contents: ${contents}`);
})
.catch(onMessage)
.catch(onMessage);
}
</script>

@ -1,41 +1,41 @@
<script>
import { listen, emit } from '@tauri-apps/api/event'
import { invoke } from '@tauri-apps/api/tauri'
import { onMount, onDestroy } from 'svelte'
import { appWindow } from "@tauri-apps/plugin-window";
import { invoke } from "@tauri-apps/api/tauri";
import { onMount, onDestroy } from "svelte";
export let onMessage
let unlisten
export let onMessage;
let unlisten;
onMount(async () => {
unlisten = await listen('rust-event', onMessage)
})
unlisten = await appWindow.listen("rust-event", onMessage);
});
onDestroy(() => {
if (unlisten) {
unlisten()
unlisten();
}
})
});
function log() {
invoke('log_operation', {
event: 'tauri-click',
payload: 'this payload is optional because we used Option in Rust'
})
invoke("log_operation", {
event: "tauri-click",
payload: "this payload is optional because we used Option in Rust",
});
}
function performRequest() {
invoke('perform_request', {
endpoint: 'dummy endpoint arg',
invoke("perform_request", {
endpoint: "dummy endpoint arg",
body: {
id: 5,
name: 'test'
}
name: "test",
},
})
.then(onMessage)
.catch(onMessage)
.catch(onMessage);
}
function emitEvent() {
emit('js-event', 'this is the payload string')
appWindow.emit("js-event", "this is the payload string");
}
</script>

@ -1,89 +1,102 @@
<script>
import { open, save } from 'tauri-plugin-dialog-api'
import { readBinaryFile } from 'tauri-plugin-fs-api'
import { open, save, confirm } from "@tauri-apps/plugin-dialog";
import { readBinaryFile } from "@tauri-apps/plugin-fs";
export let onMessage
export let insecureRenderHtml
let defaultPath = null
let filter = null
let multiple = false
let directory = false
export let onMessage;
export let insecureRenderHtml;
let defaultPath = null;
let filter = null;
let multiple = false;
let directory = false;
function arrayBufferToBase64(buffer, callback) {
var blob = new Blob([buffer], {
type: 'application/octet-binary'
})
var reader = new FileReader()
type: "application/octet-binary",
});
var reader = new FileReader();
reader.onload = function (evt) {
var dataurl = evt.target.result
callback(dataurl.substr(dataurl.indexOf(',') + 1))
}
reader.readAsDataURL(blob)
var dataurl = evt.target.result;
callback(dataurl.substr(dataurl.indexOf(",") + 1));
};
reader.readAsDataURL(blob);
}
async function prompt() {
confirm("Is Tauri awesome?", {
okLabel: "Absolutely",
cancelLabel: "Totally",
})
.then((res) =>
onMessage(
res ? "Tauri is absolutely awesome" : "Tauri is totally awesome"
)
)
.catch(onMessage);
}
function openDialog() {
open({
title: 'My wonderful open dialog',
title: "My wonderful open dialog",
defaultPath,
filters: filter
? [
{
name: 'Tauri Example',
extensions: filter.split(',').map((f) => f.trim())
}
name: "Tauri Example",
extensions: filter.split(",").map((f) => f.trim()),
},
]
: [],
multiple,
directory
directory,
})
.then(function (res) {
if (Array.isArray(res)) {
onMessage(res)
onMessage(res);
} else {
var pathToRead = typeof res === 'string' ? res : res.path
var isFile = pathToRead.match(/\S+\.\S+$/g)
var pathToRead = typeof res === "string" ? res : res.path;
var isFile = pathToRead.match(/\S+\.\S+$/g);
readBinaryFile(pathToRead)
.then(function (response) {
if (isFile) {
if (
pathToRead.includes('.png') ||
pathToRead.includes('.jpg')
pathToRead.includes(".png") ||
pathToRead.includes(".jpg")
) {
arrayBufferToBase64(
new Uint8Array(response),
function (base64) {
var src = 'data:image/png;base64,' + base64
insecureRenderHtml('<img src="' + src + '"></img>')
var src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>');
}
)
);
} else {
onMessage(res)
onMessage(res);
}
} else {
onMessage(res)
onMessage(res);
}
})
.catch(onMessage(res))
.catch(onMessage(res));
}
})
.catch(onMessage)
.catch(onMessage);
}
function saveDialog() {
save({
title: 'My wonderful save dialog',
title: "My wonderful save dialog",
defaultPath,
filters: filter
? [
{
name: 'Tauri Example',
extensions: filter.split(',').map((f) => f.trim())
}
name: "Tauri Example",
extensions: filter.split(",").map((f) => f.trim()),
},
]
: []
: [],
})
.then(onMessage)
.catch(onMessage)
.catch(onMessage);
}
</script>
@ -116,3 +129,4 @@
<button class="btn" id="save-dialog" on:click={saveDialog}
>Open save dialog</button
>
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>

@ -3,79 +3,79 @@
readBinaryFile,
writeTextFile,
readDir,
Dir
} from 'tauri-plugin-fs-api'
import { convertFileSrc } from '@tauri-apps/api/tauri'
Dir,
} from "@tauri-apps/plugin-fs";
import { convertFileSrc } from "@tauri-apps/api/tauri";
export let onMessage
export let insecureRenderHtml
export let onMessage;
export let insecureRenderHtml;
let pathToRead = ''
let img
let pathToRead = "";
let img;
function getDir() {
const dirSelect = document.getElementById('dir')
return dirSelect.value ? parseInt(dir.value) : null
const dirSelect = document.getElementById("dir");
return dirSelect.value ? parseInt(dir.value) : null;
}
function arrayBufferToBase64(buffer, callback) {
const blob = new Blob([buffer], {
type: 'application/octet-binary'
})
const reader = new FileReader()
type: "application/octet-binary",
});
const reader = new FileReader();
reader.onload = function (evt) {
const dataurl = evt.target.result
callback(dataurl.substr(dataurl.indexOf(',') + 1))
}
reader.readAsDataURL(blob)
const dataurl = evt.target.result;
callback(dataurl.substr(dataurl.indexOf(",") + 1));
};
reader.readAsDataURL(blob);
}
const DirOptions = Object.keys(Dir)
.filter((key) => isNaN(parseInt(key)))
.map((dir) => [dir, Dir[dir]])
.map((dir) => [dir, Dir[dir]]);
function read() {
const isFile = pathToRead.match(/\S+\.\S+$/g)
const isFile = pathToRead.match(/\S+\.\S+$/g);
const opts = {
dir: getDir()
}
dir: getDir(),
};
const promise = isFile
? readBinaryFile(pathToRead, opts)
: readDir(pathToRead, opts)
: readDir(pathToRead, opts);
promise
.then(function (response) {
if (isFile) {
if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) {
if (pathToRead.includes(".png") || pathToRead.includes(".jpg")) {
arrayBufferToBase64(new Uint8Array(response), function (base64) {
const src = 'data:image/png;base64,' + base64
insecureRenderHtml('<img src="' + src + '"></img>')
})
const src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>');
});
} else {
const value = String.fromCharCode.apply(null, response)
const value = String.fromCharCode.apply(null, response);
insecureRenderHtml(
'<textarea id="file-response"></textarea><button id="file-save">Save</button>'
)
);
setTimeout(() => {
const fileInput = document.getElementById('file-response')
fileInput.value = value
const fileInput = document.getElementById("file-response");
fileInput.value = value;
document
.getElementById('file-save')
.addEventListener('click', function () {
.getElementById("file-save")
.addEventListener("click", function () {
writeTextFile(pathToRead, fileInput.value, {
dir: getDir()
}).catch(onMessage)
})
})
dir: getDir(),
}).catch(onMessage);
});
});
}
} else {
onMessage(response)
onMessage(response);
}
})
.catch(onMessage)
.catch(onMessage);
}
function setSrc() {
img.src = convertFileSrc(pathToRead)
img.src = convertFileSrc(pathToRead);
}
</script>

@ -1,60 +1,60 @@
<script>
import { getClient, Body, ResponseType } from 'tauri-plugin-http-api'
import { JsonView } from '@zerodevx/svelte-json-view'
import { getClient, Body, ResponseType } from "@tauri-apps/plugin-http";
import { JsonView } from "@zerodevx/svelte-json-view";
let httpMethod = 'GET'
let httpBody = ''
let httpMethod = "GET";
let httpBody = "";
export let onMessage
export let onMessage;
async function makeHttpRequest() {
const client = await getClient().catch((e) => {
onMessage(e)
throw e
})
let method = httpMethod || 'GET'
onMessage(e);
throw e;
});
let method = httpMethod || "GET";
const options = {
url: 'http://localhost:3003',
method: method || 'GET'
}
url: "http://localhost:3003",
method: method || "GET",
};
if (
(httpBody.startsWith('{') && httpBody.endsWith('}')) ||
(httpBody.startsWith('[') && httpBody.endsWith(']'))
(httpBody.startsWith("{") && httpBody.endsWith("}")) ||
(httpBody.startsWith("[") && httpBody.endsWith("]"))
) {
options.body = Body.json(JSON.parse(httpBody))
} else if (httpBody !== '') {
options.body = Body.text(httpBody)
options.body = Body.json(JSON.parse(httpBody));
} else if (httpBody !== "") {
options.body = Body.text(httpBody);
}
client.request(options).then(onMessage).catch(onMessage)
client.request(options).then(onMessage).catch(onMessage);
}
/// http form
let foo = 'baz'
let bar = 'qux'
let result = null
let multipart = true
let foo = "baz";
let bar = "qux";
let result = null;
let multipart = true;
async function doPost() {
const client = await getClient().catch((e) => {
onMessage(e)
throw e
})
onMessage(e);
throw e;
});
result = await client.request({
url: 'http://localhost:3003',
method: 'POST',
url: "http://localhost:3003",
method: "POST",
body: Body.form({
foo,
bar
bar,
}),
headers: multipart
? { 'Content-Type': 'multipart/form-data' }
? { "Content-Type": "multipart/form-data" }
: undefined,
responseType: ResponseType.Text
})
responseType: ResponseType.Text,
});
}
</script>

@ -1,5 +1,5 @@
<script>
import { scan } from "tauri-plugin-barcode-scanner-api";
import { scan } from "@tauri-apps/plugin-barcode-scanner";
export let onMessage;

@ -1,65 +1,65 @@
<script>
import { Command } from 'tauri-plugin-shell-api'
import { Command } from "@tauri-apps/plugin-shell";
const windows = navigator.userAgent.includes('Windows')
let cmd = windows ? 'cmd' : 'sh'
let args = windows ? ['/C'] : ['-c']
const windows = navigator.userAgent.includes("Windows");
let cmd = windows ? "cmd" : "sh";
let args = windows ? ["/C"] : ["-c"];
export let onMessage
export let onMessage;
let script = 'echo "hello world"'
let cwd = null
let env = 'SOMETHING=value ANOTHER=2'
let encoding = ''
let stdin = ''
let child
let script = 'echo "hello world"';
let cwd = null;
let env = "SOMETHING=value ANOTHER=2";
let encoding = "";
let stdin = "";
let child;
function _getEnv() {
return env.split(' ').reduce((env, clause) => {
let [key, value] = clause.split('=')
return env.split(" ").reduce((env, clause) => {
let [key, value] = clause.split("=");
return {
...env,
[key]: value
}
}, {})
[key]: value,
};
}, {});
}
function spawn() {
child = null
child = null;
const command = Command.create(cmd, [...args, script], {
cwd: cwd || null,
env: _getEnv(),
encoding: encoding || undefined,
})
});
command.on('close', (data) => {
command.on("close", (data) => {
onMessage(
`command finished with code ${data.code} and signal ${data.signal}`
)
child = null
})
command.on('error', (error) => onMessage(`command error: "${error}"`))
);
child = null;
});
command.on("error", (error) => onMessage(`command error: "${error}"`));
command.stdout.on('data', (line) => onMessage(`command stdout: "${line}"`))
command.stderr.on('data', (line) => onMessage(`command stderr: "${line}"`))
command.stdout.on("data", (line) => onMessage(`command stdout: "${line}"`));
command.stderr.on("data", (line) => onMessage(`command stderr: "${line}"`));
command
.spawn()
.then((c) => {
child = c
child = c;
})
.catch(onMessage)
.catch(onMessage);
}
function kill() {
child
.kill()
.then(() => onMessage('killed child process'))
.catch(onMessage)
.then(() => onMessage("killed child process"))
.catch(onMessage);
}
function writeToStdin() {
child.write(stdin).catch(onMessage)
child.write(stdin).catch(onMessage);
}
</script>

@ -1,46 +1,46 @@
<script>
import { writable } from 'svelte/store'
import { writable } from "svelte/store";
import {
register as registerShortcut,
unregister as unregisterShortcut,
unregisterAll as unregisterAllShortcuts
} from 'tauri-plugin-global-shortcut-api'
unregisterAll as unregisterAllShortcuts,
} from "@tauri-apps/plugin-global-shortcut";
export let onMessage
const shortcuts = writable([])
let shortcut = 'CmdOrControl+X'
export let onMessage;
const shortcuts = writable([]);
let shortcut = "CmdOrControl+X";
function register() {
const shortcut_ = shortcut
const shortcut_ = shortcut;
registerShortcut(shortcut_, () => {
onMessage(`Shortcut ${shortcut_} triggered`)
onMessage(`Shortcut ${shortcut_} triggered`);
})
.then(() => {
shortcuts.update((shortcuts_) => [...shortcuts_, shortcut_])
onMessage(`Shortcut ${shortcut_} registered successfully`)
shortcuts.update((shortcuts_) => [...shortcuts_, shortcut_]);
onMessage(`Shortcut ${shortcut_} registered successfully`);
})
.catch(onMessage)
.catch(onMessage);
}
function unregister(shortcut) {
const shortcut_ = shortcut
const shortcut_ = shortcut;
unregisterShortcut(shortcut_)
.then(() => {
shortcuts.update((shortcuts_) =>
shortcuts_.filter((s) => s !== shortcut_)
)
onMessage(`Shortcut ${shortcut_} unregistered`)
);
onMessage(`Shortcut ${shortcut_} unregistered`);
})
.catch(onMessage)
.catch(onMessage);
}
function unregisterAll() {
unregisterAllShortcuts()
.then(() => {
shortcuts.update(() => [])
onMessage(`Unregistered all shortcuts`)
shortcuts.update(() => []);
onMessage(`Unregistered all shortcuts`);
})
.catch(onMessage)
.catch(onMessage);
}
</script>

@ -1,76 +1,86 @@
<script>
import { onMount, onDestroy } from 'svelte'
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
// This example show how updater events work when dialog is disabled.
// This allow you to use custom dialog for the updater.
// This is your responsibility to restart the application after you receive the STATUS: DONE.
export let onMessage;
import { checkUpdate, installUpdate } from '@tauri-apps/api/updater'
import { listen } from '@tauri-apps/api/event'
import { relaunch } from '@tauri-apps/api/process'
let isChecking, isInstalling, newUpdate;
let totalSize = 0,
downloadedSize = 0;
export let onMessage
let unlisten
onMount(async () => {
unlisten = await listen('tauri://update-status', onMessage)
})
onDestroy(() => {
if (unlisten) {
unlisten()
}
})
let isChecking, isInstalling, newUpdate
async function check() {
isChecking = true
async function checkUpdate() {
isChecking = true;
try {
const { shouldUpdate, manifest } = await checkUpdate()
onMessage(`Should update: ${shouldUpdate}`)
onMessage(manifest)
const update = await check();
onMessage(`Should update: ${update.response.available}`);
onMessage(update.response);
newUpdate = shouldUpdate
newUpdate = update;
} catch (e) {
onMessage(e)
onMessage(e);
} finally {
isChecking = false
isChecking = false;
}
}
async function install() {
isInstalling = true
isInstalling = true;
downloadedSize = 0;
try {
await installUpdate()
onMessage('Installation complete, restart required.')
await relaunch()
await newUpdate.downloadAndInstall((downloadProgress) => {
switch (downloadProgress.event) {
case "Started":
totalSize = downloadProgress.data.contentLength;
break;
case "Progress":
downloadedSize += downloadProgress.data.chunkLength;
break;
case "Finished":
break;
}
});
onMessage("Installation complete, restarting...");
await new Promise((resolve) => setTimeout(resolve, 2000));
await relaunch();
} catch (e) {
onMessage(e)
console.error(e);
onMessage(e);
} finally {
isInstalling = false
isInstalling = false;
}
}
$: progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0;
</script>
<div class="flex children:grow children:h10">
{#if !isChecking && !newUpdate}
<button class="btn" on:click={check}>Check update</button>
<button class="btn" on:click={checkUpdate}>Check update</button>
{:else if !isInstalling && newUpdate}
<button class="btn" on:click={install}>Install update</button>
{:else}
<button
class="btn text-accentText dark:text-darkAccentText flex items-center justify-center"
><div class="spinner animate-spin" /></button
>
<div class="progress">
<span>{progress}%</span>
<div class="progress-bar" style="width: {progress}%" />
</div>
{/if}
</div>
<style>
.spinner {
height: 1.2rem;
width: 1.2rem;
border-radius: 50rem;
color: currentColor;
border: 2px dashed currentColor;
.progress {
width: 100%;
height: 50px;
position: relative;
margin-top: 5%;
}
.progress > span {
font-size: 1.2rem;
}
.progress-bar {
height: 30px;
background-color: hsl(32, 94%, 46%);
border: 1px solid #333;
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save