mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-04 15:47:50 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4d1633c4d | |||
| e438e0a62d |
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
"authenticator": patch
|
||||||
|
"autostart": patch
|
||||||
|
"barcode-scanner": patch
|
||||||
|
"cli": patch
|
||||||
|
"clipboard-manager": patch
|
||||||
|
"deep-link": patch
|
||||||
|
"dialog": patch
|
||||||
|
"fs": patch
|
||||||
|
"global-shortcut": patch
|
||||||
|
"http": patch
|
||||||
|
"localhost": patch
|
||||||
|
"log-plugin": patch
|
||||||
|
"notification": patch
|
||||||
|
"os": patch
|
||||||
|
"persisted-scope": patch
|
||||||
|
"positioner": patch
|
||||||
|
"process": patch
|
||||||
|
"shell": patch
|
||||||
|
"single-instance": patch
|
||||||
|
"sql": patch
|
||||||
|
"store": patch
|
||||||
|
"stronghold": patch
|
||||||
|
"updater": patch
|
||||||
|
"upload": patch
|
||||||
|
"websocket": patch
|
||||||
|
"window-state": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Update to tauri@alpha.17.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
"authenticator-js": patch
|
||||||
|
"autostart-js": patch
|
||||||
|
"barcode-scanner-js": patch
|
||||||
|
"cli-js": patch
|
||||||
|
"clipboard-manager-js": patch
|
||||||
|
"deep-link-js": patch
|
||||||
|
"dialog-js": patch
|
||||||
|
"fs-js": patch
|
||||||
|
"global-shortcut-js": patch
|
||||||
|
"http-js": patch
|
||||||
|
"log-js": patch
|
||||||
|
"notification-js": patch
|
||||||
|
"os-js": patch
|
||||||
|
"positioner-js": patch
|
||||||
|
"process-js": patch
|
||||||
|
"shell-js": patch
|
||||||
|
"sql-js": patch
|
||||||
|
"store-js": patch
|
||||||
|
"stronghold-js": patch
|
||||||
|
"updater-js": patch
|
||||||
|
"upload-js": patch
|
||||||
|
"websocket-js": patch
|
||||||
|
"window-state-js": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
@@ -24,4 +24,4 @@
|
|||||||
"window-state-js": patch
|
"window-state-js": patch
|
||||||
---
|
---
|
||||||
|
|
||||||
Update to @tauri-apps/api v2.0.0-alpha.16.
|
Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"log-plugin": patch
|
||||||
|
"deep-link": patch
|
||||||
|
"store": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Update to breaking changes from tauri@alpha.17.
|
||||||
@@ -2,10 +2,13 @@
|
|||||||
"tag": "alpha",
|
"tag": "alpha",
|
||||||
"changes": [
|
"changes": [
|
||||||
".changes/alpha.16.md",
|
".changes/alpha.16.md",
|
||||||
|
".changes/alpha.17.md",
|
||||||
|
".changes/api-alpha.11.md",
|
||||||
".changes/api-alpha.9.md",
|
".changes/api-alpha.9.md",
|
||||||
".changes/deep-link-initial-release.md",
|
".changes/deep-link-initial-release.md",
|
||||||
".changes/dialog-async-message-dialog.md",
|
".changes/dialog-async-message-dialog.md",
|
||||||
".changes/fix-docs-build.md",
|
".changes/fix-docs-build.md",
|
||||||
|
".changes/fix-emit-all-usage.md",
|
||||||
".changes/fix-invoke-usage.md",
|
".changes/fix-invoke-usage.md",
|
||||||
".changes/fix-permission-notification.md",
|
".changes/fix-permission-notification.md",
|
||||||
".changes/fix-updater-macos.md",
|
".changes/fix-updater-macos.md",
|
||||||
|
|||||||
Generated
+300
-301
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -5,8 +5,8 @@ resolver = "2"
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
tauri = "2.0.0-alpha.16"
|
tauri = "2.0.0-alpha.17"
|
||||||
tauri-build = "2.0.0-alpha.10"
|
tauri-build = "2.0.0-alpha.11"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.5]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `barcode-scanner-js@2.0.0-alpha.2`
|
||||||
|
- Upgraded to `cli-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `clipboard-manager-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `dialog-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `fs-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `global-shortcut-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `http-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `log-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `notification-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `os-js@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `process-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `shell-js@2.0.0-alpha.3`
|
||||||
|
- Upgraded to `updater-js@2.0.0-alpha.3`
|
||||||
|
|
||||||
## \[2.0.0-alpha.4]
|
## \[2.0.0-alpha.4]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
+15
-15
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "svelte-app",
|
"name": "svelte-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.0-alpha.4",
|
"version": "2.0.0-alpha.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --clearScreen false",
|
"dev": "vite --clearScreen false",
|
||||||
@@ -9,26 +9,26 @@
|
|||||||
"serve": "vite preview"
|
"serve": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9",
|
"@tauri-apps/api": "2.0.0-alpha.11",
|
||||||
"@tauri-apps/plugin-barcode-scanner": "2.0.0-alpha.1",
|
"@tauri-apps/plugin-barcode-scanner": "2.0.0-alpha.2",
|
||||||
"@tauri-apps/plugin-cli": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-cli": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-clipboard-manager": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-dialog": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-dialog": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-fs": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-fs": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-global-shortcut": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-global-shortcut": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-http": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-http": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-notification": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-notification": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-os": "2.0.0-alpha.3",
|
"@tauri-apps/plugin-os": "2.0.0-alpha.4",
|
||||||
"@tauri-apps/plugin-process": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-process": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-shell": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-shell": "2.0.0-alpha.3",
|
||||||
"@tauri-apps/plugin-updater": "2.0.0-alpha.2",
|
"@tauri-apps/plugin-updater": "2.0.0-alpha.3",
|
||||||
"@zerodevx/svelte-json-view": "1.0.7"
|
"@zerodevx/svelte-json-view": "1.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/codicon": "^1.1.31",
|
"@iconify-json/codicon": "^1.1.31",
|
||||||
"@iconify-json/ph": "^1.1.6",
|
"@iconify-json/ph": "^1.1.6",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.6",
|
"@sveltejs/vite-plugin-svelte": "^2.4.6",
|
||||||
"@tauri-apps/cli": "2.0.0-alpha.16",
|
"@tauri-apps/cli": "2.0.0-alpha.17",
|
||||||
"@unocss/extractor-svelte": "^0.56.5",
|
"@unocss/extractor-svelte": "^0.56.5",
|
||||||
"internal-ip": "^8.0.0",
|
"internal-ip": "^8.0.0",
|
||||||
"svelte": "^4.2.2",
|
"svelte": "^4.2.2",
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.7]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `barcode-scanner@2.0.0-alpha.2`
|
||||||
|
- Upgraded to `cli@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `clipboard-manager@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `dialog@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `fs@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `global-shortcut@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `http@2.0.0-alpha.5`
|
||||||
|
- Upgraded to `log-plugin@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `notification@2.0.0-alpha.5`
|
||||||
|
- Upgraded to `os@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `process@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `shell@2.0.0-alpha.4`
|
||||||
|
- Upgraded to `updater@2.0.0-alpha.4`
|
||||||
|
|
||||||
## \[2.0.0-alpha.6]
|
## \[2.0.0-alpha.6]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "api"
|
name = "api"
|
||||||
publish = false
|
publish = false
|
||||||
version = "2.0.0-alpha.6"
|
version = "2.0.0-alpha.7"
|
||||||
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 }
|
||||||
@@ -18,15 +18,15 @@ serde_json = { workspace = true }
|
|||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
tiny_http = "0.11"
|
tiny_http = "0.11"
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.0-alpha.3" }
|
tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.0-alpha.3" }
|
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.0-alpha.3" }
|
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-alpha.3" }
|
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ], version = "2.0.0-alpha.4" }
|
tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ], version = "2.0.0-alpha.5" }
|
||||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-alpha.4", features = [ "windows7-compat" ] }
|
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-alpha.5", features = [ "windows7-compat" ] }
|
||||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-alpha.3" }
|
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-alpha.3" }
|
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.3" }
|
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.4" }
|
||||||
|
|
||||||
[dependencies.tauri]
|
[dependencies.tauri]
|
||||||
workspace = true
|
workspace = true
|
||||||
@@ -40,12 +40,12 @@ tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.3
|
|||||||
]
|
]
|
||||||
|
|
||||||
[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.0.0-alpha.3" }
|
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.0.0-alpha.3" }
|
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.0.0-alpha.4" }
|
||||||
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-alpha.3" }
|
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-alpha.4" }
|
||||||
|
|
||||||
[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.0.0-alpha.1" }
|
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.0.0-alpha.2" }
|
||||||
|
|
||||||
[target."cfg(target_os = \"windows\")".dependencies]
|
[target."cfg(target_os = \"windows\")".dependencies]
|
||||||
window-shadows = "0.2"
|
window-shadows = "0.2"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<application
|
<application
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>NSCameraUsageDescription</key>
|
||||||
|
<string>Request camera access for barcode scanner</string>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ mod cmd;
|
|||||||
mod tray;
|
mod tray;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tauri::{window::WindowBuilder, App, AppHandle, RunEvent, WindowUrl};
|
use tauri::{window::WindowBuilder, App, AppHandle, Manager, RunEvent, WindowUrl};
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
struct Reply {
|
struct Reply {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
component: Http,
|
component: Http,
|
||||||
icon: "i-ph-globe-hemisphere-west",
|
icon: "i-ph-globe-hemisphere-west",
|
||||||
},
|
},
|
||||||
!isMobile && {
|
{
|
||||||
label: "Notifications",
|
label: "Notifications",
|
||||||
component: Notifications,
|
component: Notifications,
|
||||||
icon: "i-codicon-bell-dot",
|
icon: "i-codicon-bell-dot",
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
component: Updater,
|
component: Updater,
|
||||||
icon: "i-codicon-cloud-download",
|
icon: "i-codicon-cloud-download",
|
||||||
},
|
},
|
||||||
!isMobile && {
|
{
|
||||||
label: "Clipboard",
|
label: "Clipboard",
|
||||||
component: Clipboard,
|
component: Clipboard,
|
||||||
icon: "i-codicon-clippy",
|
icon: "i-codicon-clippy",
|
||||||
|
|||||||
@@ -29,6 +29,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button class="btn" id="notification" on:click={_sendNotification}>
|
<button class="btn" id="notification" on:click={sendNotification}>
|
||||||
Send test notification
|
Send test notification
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-authenticator"
|
name = "tauri-plugin-authenticator"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
description = "Use hardware security-keys in your Tauri App."
|
description = "Use hardware security-keys in your Tauri App."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-authenticator",
|
"name": "@tauri-apps/plugin-authenticator",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"description": "Use hardware security-keys in your Tauri App.",
|
"description": "Use hardware security-keys in your Tauri App.",
|
||||||
"license": "MIT or APACHE-2.0",
|
"license": "MIT or APACHE-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
"tslib": "2.6.0"
|
"tslib": "2.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_AUTHENTICATOR__=function(e){"use strict";var t=Object.defineProperty,n=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)},i=(e,t,i)=>(n(e,t,"read from private field"),i?i.call(e):t.get(e));function a(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((e,n)=>{for(var i in n)t(e,i,{get:n[i],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>c,addPluginListener:()=>l,convertFileSrc:()=>u,invoke:()=>o,transformCallback:()=>a});var r,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,t,n)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)})(this,r,(()=>{})),this.id=a((e=>{i(this,r).call(this,e)}))}set onmessage(e){var t,i,a,s;a=e,n(t=this,i=r,"write to private field"),s?s.call(t,a):i.set(t,a)}get onmessage(){return i(this,r)}toJSON(){return`__CHANNEL__:${this.id}`}};r=new WeakMap;var c=class{constructor(e,t,n){this.plugin=e,this.event=t,this.channelId=n}async unregister(){return o(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function l(e,t,n){let i=new s;return i.onmessage=n,o(`plugin:${e}|register_listener`,{event:t,handler:i}).then((()=>new c(e,t,i.id)))}async function o(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}function u(e,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,t)}return e.Authenticator=class{async init(){return await o("plugin:authenticator|init_auth")}async register(e,t){return await o("plugin:authenticator|register",{timeout:1e4,challenge:e,application:t})}async verifyRegistration(e,t,n,i){return await o("plugin:authenticator|verify_registration",{challenge:e,application:t,registerData:n,clientData:i})}async sign(e,t,n){return await o("plugin:authenticator|sign",{timeout:1e4,challenge:e,application:t,keyHandle:n})}async verifySignature(e,t,n,i,a,r){return await o("plugin:authenticator|verify_signature",{challenge:e,application:t,signData:n,clientData:i,keyHandle:a,pubkey:r})}},e}({});Object.defineProperty(window.__TAURI__,"authenticator",{value:__TAURI_AUTHENTICATOR__})}
|
if("__TAURI__"in window){var __TAURI_AUTHENTICATOR__=function(t){"use strict";async function i(t,i={},a){return window.__TAURI_INTERNALS__.invoke(t,i,a)}"function"==typeof SuppressedError&&SuppressedError;return t.Authenticator=class{async init(){return await i("plugin:authenticator|init_auth")}async register(t,a){return await i("plugin:authenticator|register",{timeout:1e4,challenge:t,application:a})}async verifyRegistration(t,a,e,n){return await i("plugin:authenticator|verify_registration",{challenge:t,application:a,registerData:e,clientData:n})}async sign(t,a,e){return await i("plugin:authenticator|sign",{timeout:1e4,challenge:t,application:a,keyHandle:e})}async verifySignature(t,a,e,n,r,u){return await i("plugin:authenticator|verify_signature",{challenge:t,application:a,signData:e,clientData:n,keyHandle:r,pubkey:u})}},t}({});Object.defineProperty(window.__TAURI__,"authenticator",{value:__TAURI_AUTHENTICATOR__})}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-autostart"
|
name = "tauri-plugin-autostart"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
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 }
|
||||||
@@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-autostart",
|
"name": "@tauri-apps/plugin-autostart",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "2.6.0"
|
"tslib": "2.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_AUTOSTART__=function(e){"use strict";var n=Object.defineProperty,t=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},r=(e,n,r)=>(t(e,n,"read from private field"),r?r.call(e):n.get(e));function a(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}((e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>o,addPluginListener:()=>_,convertFileSrc:()=>c,invoke:()=>l,transformCallback:()=>a});var i,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,i,(()=>{})),this.id=a((e=>{r(this,i).call(this,e)}))}set onmessage(e){var n,r,a,s;a=e,t(n=this,r=i,"write to private field"),s?s.call(n,a):r.set(n,a)}get onmessage(){return r(this,i)}toJSON(){return`__CHANNEL__:${this.id}`}};i=new WeakMap;var o=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return l(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function _(e,n,t){let r=new s;return r.onmessage=t,l(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new o(e,n,r.id)))}async function l(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function c(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}return e.disable=async function(){await l("plugin:autostart|disable")},e.enable=async function(){await l("plugin:autostart|enable")},e.isEnabled=async function(){return await l("plugin:autostart|is_enabled")},e}({});Object.defineProperty(window.__TAURI__,"autostart",{value:__TAURI_AUTOSTART__})}
|
if("__TAURI__"in window){var __TAURI_AUTOSTART__=function(n){"use strict";async function t(n,t={},a){return window.__TAURI_INTERNALS__.invoke(n,t,a)}return"function"==typeof SuppressedError&&SuppressedError,n.disable=async function(){await t("plugin:autostart|disable")},n.enable=async function(){await t("plugin:autostart|enable")},n.isEnabled=async function(){return await t("plugin:autostart|is_enabled")},n}({});Object.defineProperty(window.__TAURI__,"autostart",{value:__TAURI_AUTOSTART__})}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.1]
|
## \[2.0.0-alpha.1]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-barcode-scanner"
|
name = "tauri-plugin-barcode-scanner"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
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 }
|
||||||
@@ -9,7 +9,8 @@ rust-version = { workspace = true }
|
|||||||
links = "tauri-plugin-barcode-scanner"
|
links = "tauri-plugin-barcode-scanner"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
targets = [ "x86_64-linux-android" ]
|
targets = [ "x86_64-linux-android" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -21,6 +22,3 @@ serde_json = { workspace = true }
|
|||||||
tauri = { workspace = true }
|
tauri = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
[features]
|
|
||||||
dox = [ "tauri/dox" ]
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import app.tauri.Logger
|
|||||||
import app.tauri.PermissionState
|
import app.tauri.PermissionState
|
||||||
import app.tauri.annotation.ActivityCallback
|
import app.tauri.annotation.ActivityCallback
|
||||||
import app.tauri.annotation.Command
|
import app.tauri.annotation.Command
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.annotation.Permission
|
import app.tauri.annotation.Permission
|
||||||
import app.tauri.annotation.PermissionCallback
|
import app.tauri.annotation.PermissionCallback
|
||||||
import app.tauri.annotation.TauriPlugin
|
import app.tauri.annotation.TauriPlugin
|
||||||
@@ -57,6 +58,13 @@ 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"
|
private const val PREFS_PERMISSION_FIRST_TIME_ASKING = "PREFS_PERMISSION_FIRST_TIME_ASKING"
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class ScanOptions {
|
||||||
|
var formats: Array<String>? = null
|
||||||
|
var windowed: Boolean = false
|
||||||
|
var cameraDirection: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
@TauriPlugin(
|
@TauriPlugin(
|
||||||
permissions = [
|
permissions = [
|
||||||
Permission(strings = [Manifest.permission.CAMERA], alias = "camera")
|
Permission(strings = [Manifest.permission.CAMERA], alias = "camera")
|
||||||
@@ -206,20 +214,13 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFormats(invoke: Invoke): List<Int> {
|
private fun getFormats(args: ScanOptions): List<Int> {
|
||||||
val jsFormats = invoke.getArray("formats", JSArray())
|
|
||||||
val formats = ArrayList<Int>()
|
val formats = ArrayList<Int>()
|
||||||
for (i in 0 until jsFormats.length()) {
|
for (format in args.formats ?: arrayOf()) {
|
||||||
try {
|
val targetedBarcodeFormat = supportedFormats[format]
|
||||||
val targetedFormat: String = jsFormats.getString(i)
|
|
||||||
val targetedBarcodeFormat =
|
|
||||||
supportedFormats[targetedFormat]
|
|
||||||
if (targetedBarcodeFormat != null) {
|
if (targetedBarcodeFormat != null) {
|
||||||
formats.add(targetedBarcodeFormat)
|
formats.add(targetedBarcodeFormat)
|
||||||
}
|
}
|
||||||
} catch (e: JSONException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return formats
|
return formats
|
||||||
}
|
}
|
||||||
@@ -341,14 +342,16 @@ class BarcodeScannerPlugin(private val activity: Activity) : Plugin(activity),
|
|||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun scan(invoke: Invoke) {
|
fun scan(invoke: Invoke) {
|
||||||
|
val args = invoke.parseArgs(ScanOptions::class.java)
|
||||||
|
|
||||||
savedInvoke = invoke
|
savedInvoke = invoke
|
||||||
if (hasCamera()) {
|
if (hasCamera()) {
|
||||||
if (getPermissionState("camera") != PermissionState.GRANTED) {
|
if (getPermissionState("camera") != PermissionState.GRANTED) {
|
||||||
throw Exception("No permission to use camera. Did you request it yet?")
|
throw Exception("No permission to use camera. Did you request it yet?")
|
||||||
} else {
|
} else {
|
||||||
webViewBackground = null
|
webViewBackground = null
|
||||||
prepare(invoke.getString("cameraDirection", "back"), invoke.getBoolean("windowed", false))
|
prepare(args.cameraDirection ?: "back", args.windowed)
|
||||||
configureCamera(getFormats(invoke))
|
configureCamera(getFormats(args))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fn main() {
|
|||||||
{
|
{
|
||||||
println!("{error:#}");
|
println!("{error:#}");
|
||||||
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
||||||
if !(cfg!(feature = "dox") && std::env::var("TARGET").unwrap().contains("android")) {
|
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,13 @@ import Tauri
|
|||||||
import UIKit
|
import UIKit
|
||||||
import WebKit
|
import WebKit
|
||||||
|
|
||||||
enum SupportedFormat: String, CaseIterable {
|
struct ScanOptions: Decodable {
|
||||||
|
var formats: [SupportedFormat] = []
|
||||||
|
let windowed: Bool?
|
||||||
|
let cameraDirection: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SupportedFormat: String, CaseIterable, Decodable {
|
||||||
// UPC_A not supported
|
// UPC_A not supported
|
||||||
case UPC_E
|
case UPC_E
|
||||||
case EAN_8
|
case EAN_8
|
||||||
@@ -232,19 +238,11 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func runScanner(_ invoke: Invoke) {
|
private func runScanner(_ invoke: Invoke, args: ScanOptions) {
|
||||||
scanFormats = [AVMetadataObject.ObjectType]()
|
scanFormats = [AVMetadataObject.ObjectType]()
|
||||||
|
|
||||||
if (invoke.data["formats"]) != nil {
|
args.formats.forEach { format in
|
||||||
let _scanFormats = invoke.getArray("formats", String.self)
|
scanFormats.append(format.value)
|
||||||
|
|
||||||
if _scanFormats != nil && _scanFormats?.count ?? 0 > 0 {
|
|
||||||
_scanFormats?.forEach { targetedFormat in
|
|
||||||
if let value = SupportedFormat(rawValue: targetedFormat)?.value {
|
|
||||||
scanFormats.append(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if scanFormats.count == 0 {
|
if scanFormats.count == 0 {
|
||||||
@@ -259,7 +257,9 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
|||||||
self.isScanning = true
|
self.isScanning = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func scan(_ invoke: Invoke) {
|
@objc private func scan(_ invoke: Invoke) throws {
|
||||||
|
let args = try invoke.parseArgs(ScanOptions.self)
|
||||||
|
|
||||||
self.invoke = invoke
|
self.invoke = invoke
|
||||||
|
|
||||||
var iOS14min: Bool = false
|
var iOS14min: Bool = false
|
||||||
@@ -279,10 +279,10 @@ class BarcodeScannerPlugin: Plugin, AVCaptureMetadataOutputObjectsDelegate {
|
|||||||
self.loadCamera()
|
self.loadCamera()
|
||||||
self.dismantleCamera()
|
self.dismantleCamera()
|
||||||
self.setupCamera(
|
self.setupCamera(
|
||||||
direction: invoke.getString("cameraDirection") ?? "back",
|
direction: args.cameraDirection ?? "back",
|
||||||
windowed: invoke.getBool("windowed") ?? false
|
windowed: args.windowed ?? false
|
||||||
)
|
)
|
||||||
self.runScanner(invoke)
|
self.runScanner(invoke, args: args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-barcode-scanner",
|
"name": "@tauri-apps/plugin-barcode-scanner",
|
||||||
"version": "2.0.0-alpha.1",
|
"version": "2.0.0-alpha.2",
|
||||||
"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": [
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_BARCODESCANNER__=function(e){"use strict";var n=Object.defineProperty,t=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},r=(e,n,r)=>(t(e,n,"read from private field"),r?r.call(e):n.get(e));function a(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}((e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>o,addPluginListener:()=>_,convertFileSrc:()=>l,invoke:()=>u,transformCallback:()=>a});var i,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,i,(()=>{})),this.id=a((e=>{r(this,i).call(this,e)}))}set onmessage(e){var n,r,a,s;a=e,t(n=this,r=i,"write to private field"),s?s.call(n,a):r.set(n,a)}get onmessage(){return r(this,i)}toJSON(){return`__CHANNEL__:${this.id}`}};i=new WeakMap;var c,o=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function _(e,n,t){let r=new s;return r.onmessage=t,u(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new o(e,n,r.id)))}async function u(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function l(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}return e.Format=void 0,(c=e.Format||(e.Format={})).QRCode="QR_CODE",c.UPC_A="UPC_A",c.UPC_E="UPC_E",c.EAN8="EAN_8",c.EAN13="EAN_13",c.Code39="CODE_39",c.Code93="CODE_93",c.Code128="CODE_128",c.Codabar="CODABAR",c.ITF="ITF",c.Aztec="AZTEC",c.DataMatrix="DATA_MATRIX",c.PDF417="PDF_417",e.cancel=async function(){return await u("plugin:barcodeScanner|cancel")},e.checkPermissions=async function(){return await u("plugin:barcodeScanner|checkPermissions").then((e=>e.camera))},e.openAppSettings=async function(){return await u("plugin:barcodeScanner|openAppSettings")},e.requestPermissions=async function(){return await u("plugin:barcodeScanner|requestPermissions").then((e=>e.camera))},e.scan=async function(e){return await u("plugin:barcodeScanner|scan",{...e})},e}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_BARCODESCANNER__})}
|
if("__TAURI__"in window){var __TAURI_BARCODESCANNER__=function(n){"use strict";async function e(n,e={},r){return window.__TAURI_INTERNALS__.invoke(n,e,r)}var r;return"function"==typeof SuppressedError&&SuppressedError,n.Format=void 0,(r=n.Format||(n.Format={})).QRCode="QR_CODE",r.UPC_A="UPC_A",r.UPC_E="UPC_E",r.EAN8="EAN_8",r.EAN13="EAN_13",r.Code39="CODE_39",r.Code93="CODE_93",r.Code128="CODE_128",r.Codabar="CODABAR",r.ITF="ITF",r.Aztec="AZTEC",r.DataMatrix="DATA_MATRIX",r.PDF417="PDF_417",n.cancel=async function(){return await e("plugin:barcodeScanner|cancel")},n.checkPermissions=async function(){return await e("plugin:barcodeScanner|checkPermissions").then((n=>n.camera))},n.openAppSettings=async function(){return await e("plugin:barcodeScanner|openAppSettings")},n.requestPermissions=async function(){return await e("plugin:barcodeScanner|requestPermissions").then((n=>n.camera))},n.scan=async function(n){return await e("plugin:barcodeScanner|scan",{...n})},n}({});Object.defineProperty(window.__TAURI__,"barcodeScanner",{value:__TAURI_BARCODESCANNER__})}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-cli"
|
name = "tauri-plugin-cli"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
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 }
|
||||||
@@ -8,7 +8,8 @@ license = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-cli",
|
"name": "@tauri-apps/plugin-cli",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "^2.4.1"
|
"tslib": "^2.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_CLI__=function(e){"use strict";var n=Object.defineProperty,t=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},r=(e,n,r)=>(t(e,n,"read from private field"),r?r.call(e):n.get(e));function i(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}((e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>_,addPluginListener:()=>o,convertFileSrc:()=>l,invoke:()=>c,transformCallback:()=>i});var a,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,a,(()=>{})),this.id=i((e=>{r(this,a).call(this,e)}))}set onmessage(e){var n,r,i,s;i=e,t(n=this,r=a,"write to private field"),s?s.call(n,i):r.set(n,i)}get onmessage(){return r(this,a)}toJSON(){return`__CHANNEL__:${this.id}`}};a=new WeakMap;var _=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return c(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function o(e,n,t){let r=new s;return r.onmessage=t,c(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new _(e,n,r.id)))}async function c(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function l(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}return e.getMatches=async function(){return await c("plugin:cli|cli_matches")},e}({});Object.defineProperty(window.__TAURI__,"cli",{value:__TAURI_CLI__})}
|
if("__TAURI__"in window){var __TAURI_CLI__=function(_){"use strict";return"function"==typeof SuppressedError&&SuppressedError,_.getMatches=async function(){return await async function(_,n={},e){return window.__TAURI_INTERNALS__.invoke(_,n,e)}("plugin:cli|cli_matches")},_}({});Object.defineProperty(window.__TAURI__,"cli",{value:__TAURI_CLI__})}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-clipboard-manager"
|
name = "tauri-plugin-clipboard-manager"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
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 }
|
||||||
@@ -9,7 +9,8 @@ rust-version = { workspace = true }
|
|||||||
links = "tauri-plugin-clipboard-manager"
|
links = "tauri-plugin-clipboard-manager"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "dox" ]
|
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" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -24,6 +25,3 @@ thiserror = { workspace = true }
|
|||||||
|
|
||||||
[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]
|
||||||
arboard = "3"
|
arboard = "3"
|
||||||
|
|
||||||
[features]
|
|
||||||
dox = [ "tauri/dox" ]
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ dependencies {
|
|||||||
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("com.fasterxml.jackson.core:jackson-databind:2.15.3")
|
||||||
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")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
|||||||
@@ -11,11 +11,74 @@ import android.content.ClipDescription
|
|||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import app.tauri.annotation.Command
|
import app.tauri.annotation.Command
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.annotation.TauriPlugin
|
import app.tauri.annotation.TauriPlugin
|
||||||
import app.tauri.plugin.Invoke
|
import app.tauri.plugin.Invoke
|
||||||
import app.tauri.plugin.JSObject
|
|
||||||
import app.tauri.plugin.Plugin
|
import app.tauri.plugin.Plugin
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator
|
||||||
|
import com.fasterxml.jackson.core.JsonParser
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
@JsonDeserialize(using = WriteOptionsDeserializer::class)
|
||||||
|
sealed class WriteOptions {
|
||||||
|
@JsonDeserialize
|
||||||
|
class PlainText: WriteOptions() {
|
||||||
|
lateinit var text: String
|
||||||
|
var label: String? = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerialize(using = ReadClipDataSerializer::class)
|
||||||
|
sealed class ReadClipData {
|
||||||
|
class PlainText: ReadClipData() {
|
||||||
|
lateinit var text: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ReadClipDataSerializer @JvmOverloads constructor(t: Class<ReadClipData>? = null) :
|
||||||
|
StdSerializer<ReadClipData>(t) {
|
||||||
|
@Throws(IOException::class, JsonProcessingException::class)
|
||||||
|
override fun serialize(
|
||||||
|
value: ReadClipData, jgen: JsonGenerator, provider: SerializerProvider
|
||||||
|
) {
|
||||||
|
jgen.writeStartObject()
|
||||||
|
when (value) {
|
||||||
|
is ReadClipData.PlainText -> {
|
||||||
|
jgen.writeObjectFieldStart("plainText")
|
||||||
|
|
||||||
|
jgen.writeStringField("text", value.text)
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class WriteOptionsDeserializer: JsonDeserializer<WriteOptions>() {
|
||||||
|
override fun deserialize(
|
||||||
|
jsonParser: JsonParser,
|
||||||
|
deserializationContext: DeserializationContext
|
||||||
|
): WriteOptions {
|
||||||
|
val node: JsonNode = jsonParser.codec.readTree(jsonParser)
|
||||||
|
node.get("plainText")?.let {
|
||||||
|
return jsonParser.codec.treeToValue(it, WriteOptions.PlainText::class.java)
|
||||||
|
} ?: run {
|
||||||
|
throw Error("unknown write options $node")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TauriPlugin
|
@TauriPlugin
|
||||||
class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
|
class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
|
||||||
@@ -25,22 +88,14 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
|
|||||||
@Command
|
@Command
|
||||||
@Suppress("MoveVariableDeclarationIntoWhen")
|
@Suppress("MoveVariableDeclarationIntoWhen")
|
||||||
fun write(invoke: Invoke) {
|
fun write(invoke: Invoke) {
|
||||||
val options = invoke.getObject("options")
|
val args = invoke.parseArgs(WriteOptions::class.java)
|
||||||
if (options == null) {
|
|
||||||
invoke.reject("Missing `options` input")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val kind = invoke.getString("kind", "")
|
|
||||||
|
|
||||||
val clipData = when (kind) {
|
val clipData = when (args) {
|
||||||
"PlainText" -> {
|
is WriteOptions.PlainText -> {
|
||||||
val label = options.getString("label", "")
|
ClipData.newPlainText(args.label, args.text)
|
||||||
val text = options.getString("text", "")
|
|
||||||
ClipData.newPlainText(label, text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
invoke.reject("Unknown kind $kind")
|
invoke.reject("unimplemented clip data")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,10 +107,12 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
|
|||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun read(invoke: Invoke) {
|
fun read(invoke: Invoke) {
|
||||||
val (kind, options) = if (manager.hasPrimaryClip()) {
|
val data = if (manager.hasPrimaryClip()) {
|
||||||
if (manager.primaryClipDescription?.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) == true) {
|
if (manager.primaryClipDescription?.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) == true) {
|
||||||
val item: ClipData.Item = manager.primaryClip!!.getItemAt(0)
|
val item: ClipData.Item = manager.primaryClip!!.getItemAt(0)
|
||||||
Pair("PlainText", item.text)
|
val data = ReadClipData.PlainText()
|
||||||
|
data.text = item.text.toString()
|
||||||
|
data
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
// TODO
|
||||||
invoke.reject("Clipboard content reader not implemented")
|
invoke.reject("Clipboard content reader not implemented")
|
||||||
@@ -66,9 +123,6 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val response = JSObject()
|
invoke.resolveObject(data)
|
||||||
response.put("kind", kind)
|
|
||||||
response.put("options", options)
|
|
||||||
invoke.resolve(response)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fn main() {
|
|||||||
{
|
{
|
||||||
println!("{error:#}");
|
println!("{error:#}");
|
||||||
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
||||||
if !(cfg!(feature = "dox") && std::env::var("TARGET").unwrap().contains("android")) {
|
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,7 @@
|
|||||||
|
|
||||||
import { invoke } from "@tauri-apps/api/primitives";
|
import { invoke } from "@tauri-apps/api/primitives";
|
||||||
|
|
||||||
interface Clip<K, T> {
|
type ClipResponse = Record<"plainText", { text: string }>;
|
||||||
kind: K;
|
|
||||||
options: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClipResponse = Clip<"PlainText", string>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes plain text to the clipboard.
|
* Writes plain text to the clipboard.
|
||||||
@@ -36,8 +31,7 @@ async function writeText(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return invoke("plugin:clipboard|write", {
|
return invoke("plugin:clipboard|write", {
|
||||||
data: {
|
data: {
|
||||||
kind: "PlainText",
|
plainText: {
|
||||||
options: {
|
|
||||||
label: opts?.label,
|
label: opts?.label,
|
||||||
text,
|
text,
|
||||||
},
|
},
|
||||||
@@ -56,7 +50,7 @@ async function writeText(
|
|||||||
*/
|
*/
|
||||||
async function readText(): Promise<string> {
|
async function readText(): Promise<string> {
|
||||||
const kind: ClipResponse = await invoke("plugin:clipboard|read");
|
const kind: ClipResponse = await invoke("plugin:clipboard|read");
|
||||||
return kind.options;
|
return kind.plainText.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { writeText, readText };
|
export { writeText, readText };
|
||||||
|
|||||||
@@ -2,38 +2,38 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import SwiftRs
|
||||||
|
import Tauri
|
||||||
import UIKit
|
import UIKit
|
||||||
import WebKit
|
import WebKit
|
||||||
import Tauri
|
|
||||||
import SwiftRs
|
enum WriteOptions: Codable {
|
||||||
|
case plainText(text: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ReadClipData: Codable {
|
||||||
|
case plainText(text: String)
|
||||||
|
}
|
||||||
|
|
||||||
class ClipboardPlugin: Plugin {
|
class ClipboardPlugin: Plugin {
|
||||||
@objc public func write(_ invoke: Invoke) throws {
|
@objc public func write(_ invoke: Invoke) throws {
|
||||||
let options = invoke.getObject("options")
|
let options = try invoke.parseArgs(WriteOptions.self)
|
||||||
if let options = options {
|
|
||||||
let clipboard = UIPasteboard.general
|
let clipboard = UIPasteboard.general
|
||||||
let kind = invoke.getString("kind", "")
|
switch options {
|
||||||
switch kind {
|
case .plainText(let text):
|
||||||
case "PlainText":
|
|
||||||
let text = options["text"] as? String
|
|
||||||
clipboard.string = text
|
clipboard.string = text
|
||||||
default:
|
default:
|
||||||
invoke.reject("Unknown kind \(kind)")
|
invoke.unimplemented()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
} else {
|
|
||||||
invoke.reject("Missing `options` input")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func read(_ invoke: Invoke) throws {
|
@objc public func read(_ invoke: Invoke) throws {
|
||||||
let clipboard = UIPasteboard.general
|
let clipboard = UIPasteboard.general
|
||||||
if let text = clipboard.string {
|
if let text = clipboard.string {
|
||||||
invoke.resolve([
|
invoke.resolve(ReadClipData.plainText(text: text))
|
||||||
"kind": "PlainText",
|
|
||||||
"options": text
|
|
||||||
])
|
|
||||||
} else {
|
} else {
|
||||||
invoke.reject("Clipboard is empty")
|
invoke.reject("Clipboard is empty")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-clipboard-manager",
|
"name": "@tauri-apps/plugin-clipboard-manager",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "^2.4.1"
|
"tslib": "^2.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_CLIPBOARDMANAGER__=function(e){"use strict";var n=Object.defineProperty,t=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},r=(e,n,r)=>(t(e,n,"read from private field"),r?r.call(e):n.get(e));function i(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}((e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>o,addPluginListener:()=>_,convertFileSrc:()=>c,invoke:()=>l,transformCallback:()=>i});var a,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,a,(()=>{})),this.id=i((e=>{r(this,a).call(this,e)}))}set onmessage(e){var n,r,i,s;i=e,t(n=this,r=a,"write to private field"),s?s.call(n,i):r.set(n,i)}get onmessage(){return r(this,a)}toJSON(){return`__CHANNEL__:${this.id}`}};a=new WeakMap;var o=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return l(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function _(e,n,t){let r=new s;return r.onmessage=t,l(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new o(e,n,r.id)))}async function l(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function c(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}return e.readText=async function(){return(await l("plugin:clipboard|read")).options},e.writeText=async function(e,n){return l("plugin:clipboard|write",{data:{kind:"PlainText",options:{label:null==n?void 0:n.label,text:e}}})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_CLIPBOARDMANAGER__})}
|
if("__TAURI__"in window){var __TAURI_CLIPBOARDMANAGER__=function(e){"use strict";async function n(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}return"function"==typeof SuppressedError&&SuppressedError,e.readText=async function(){return(await n("plugin:clipboard|read")).plainText.text},e.writeText=async function(e,r){return n("plugin:clipboard|write",{data:{plainText:{label:null==r?void 0:r.label,text:e}}})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_CLIPBOARDMANAGER__})}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
match &self.clipboard {
|
match &self.clipboard {
|
||||||
Ok(clipboard) => {
|
Ok(clipboard) => {
|
||||||
let text = clipboard.lock().unwrap().get_text()?;
|
let text = clipboard.lock().unwrap().get_text()?;
|
||||||
Ok(ClipboardContents::PlainText(text))
|
Ok(ClipboardContents::PlainText { text })
|
||||||
}
|
}
|
||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "kind", content = "options")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum ClipKind {
|
pub enum ClipKind {
|
||||||
PlainText { label: Option<String>, text: String },
|
PlainText { label: Option<String>, text: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "kind", content = "options")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum ClipboardContents {
|
pub enum ClipboardContents {
|
||||||
PlainText(String),
|
PlainText { text: String },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.1]
|
## \[2.0.0-alpha.1]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`eccd6f9`](https://github.com/tauri-apps/plugins-workspace/commit/eccd6f977af7629255b6f5a5205666c9079a86ed)([#504](https://github.com/tauri-apps/plugins-workspace/pull/504)) Initial release.
|
- [`eccd6f9`](https://github.com/tauri-apps/plugins-workspace/commit/eccd6f977af7629255b6f5a5205666c9079a86ed)([#504](https://github.com/tauri-apps/plugins-workspace/pull/504)) Initial release.
|
||||||
|
0.0-alpha.0]
|
||||||
|
|
||||||
|
- [`eccd6f9`](https://github.com/tauri-apps/plugins-workspace/commit/eccd6f977af7629255b6f5a5205666c9079a86ed)([#504](https://github.com/tauri-apps/plugins-workspace/pull/504)) Initial release.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-deep-link"
|
name = "tauri-plugin-deep-link"
|
||||||
version = "2.0.0-alpha.1"
|
version = "2.0.0-alpha.2"
|
||||||
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 }
|
||||||
@@ -9,7 +9,8 @@ rust-version = { workspace = true }
|
|||||||
links = "tauri-plugin-deep-link"
|
links = "tauri-plugin-deep-link"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
targets = [ "x86_64-linux-android" ]
|
targets = [ "x86_64-linux-android" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -24,6 +25,3 @@ tauri = { workspace = true }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|
||||||
[features]
|
|
||||||
dox = [ "tauri/dox" ]
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ package app.tauri.deep_link
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import app.tauri.Logger
|
import app.tauri.Logger
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.annotation.Command
|
import app.tauri.annotation.Command
|
||||||
import app.tauri.annotation.TauriPlugin
|
import app.tauri.annotation.TauriPlugin
|
||||||
import app.tauri.plugin.Channel
|
import app.tauri.plugin.Channel
|
||||||
@@ -15,6 +17,11 @@ import app.tauri.plugin.JSObject
|
|||||||
import app.tauri.plugin.Plugin
|
import app.tauri.plugin.Plugin
|
||||||
import app.tauri.plugin.Invoke
|
import app.tauri.plugin.Invoke
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class SetEventHandlerArgs {
|
||||||
|
lateinit var handler: Channel
|
||||||
|
}
|
||||||
|
|
||||||
@TauriPlugin
|
@TauriPlugin
|
||||||
class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
|
class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
|
||||||
//private val implementation = Example()
|
//private val implementation = Example()
|
||||||
@@ -33,29 +40,17 @@ class DeepLinkPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
invoke.resolve(ret)
|
invoke.resolve(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @Command
|
|
||||||
fun registerListenerRust(invoke: Invoke) {
|
|
||||||
val value = invoke.getString("value") ?: ""
|
|
||||||
val ret = JSObject()
|
|
||||||
ret.put("value", this.currentUrl ?: "none")
|
|
||||||
invoke.resolve(ret)
|
|
||||||
} */
|
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun setEventHandler(invoke: Invoke) {
|
fun setEventHandler(invoke: Invoke) {
|
||||||
val channel = invoke.getChannel("handler")
|
val args = invoke.parseArgs(SetEventHandlerArgs::class.java)
|
||||||
|
this.channel = args.handler
|
||||||
if (channel == null) {
|
|
||||||
invoke.reject("`handler` not provided")
|
|
||||||
}
|
|
||||||
this.channel = channel
|
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(webView: WebView) {
|
override fun load(webView: WebView) {
|
||||||
instance = this
|
instance = this
|
||||||
|
|
||||||
var intent = activity.intent
|
val intent = activity.intent
|
||||||
|
|
||||||
if (intent.action == Intent.ACTION_VIEW) {
|
if (intent.action == Intent.ACTION_VIEW) {
|
||||||
// TODO: check if it makes sense to split up init url and last url
|
// TODO: check if it makes sense to split up init url and last url
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ fn main() {
|
|||||||
.run()
|
.run()
|
||||||
{
|
{
|
||||||
println!("{error:#}");
|
println!("{error:#}");
|
||||||
if !(cfg!(feature = "dox") && std::env::var("TARGET").unwrap().contains("android")) {
|
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[0.0.1-alpha.2]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `deep-link-js@2.0.0-alpha.2`
|
||||||
|
|
||||||
## \[0.0.1-alpha.1]
|
## \[0.0.1-alpha.1]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "deep-link-example",
|
"name": "deep-link-example",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1-alpha.1",
|
"version": "0.0.1-alpha.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -10,11 +10,11 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.6",
|
"@tauri-apps/api": "2.0.0-alpha.11",
|
||||||
"@tauri-apps/plugin-deep-link": "2.0.0-alpha.1"
|
"@tauri-apps/plugin-deep-link": "2.0.0-alpha.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "2.0.0-alpha.16",
|
"@tauri-apps/cli": "2.0.0-alpha.17",
|
||||||
"internal-ip": "^8.0.0",
|
"internal-ip": "^8.0.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.5.0"
|
"vite": "^4.5.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-deep-link",
|
"name": "@tauri-apps/plugin-deep-link",
|
||||||
"version": "2.0.0-alpha.1",
|
"version": "2.0.0-alpha.2",
|
||||||
"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": [
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_DEEPLINK__=function(e){"use strict";var n=Object.defineProperty,t=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},r=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},i=(e,n,t)=>(r(e,n,"read from private field"),t?t.call(e):n.get(e));function a(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}t({},{Channel:()=>s,PluginListener:()=>u,addPluginListener:()=>o,convertFileSrc:()=>c,invoke:()=>l,transformCallback:()=>a});var _,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,_,(()=>{})),this.id=a((e=>{i(this,_).call(this,e)}))}set onmessage(e){((e,n,t,i)=>{r(e,n,"write to private field"),i?i.call(e,t):n.set(e,t)})(this,_,e)}get onmessage(){return i(this,_)}toJSON(){return`__CHANNEL__:${this.id}`}};_=new WeakMap;var u=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return l(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function o(e,n,t){let r=new s;return r.onmessage=t,l(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new u(e,n,r.id)))}async function l(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function c(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}t({},{TauriEvent:()=>d,emit:()=>v,listen:()=>h,once:()=>I});var d=(e=>(e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_CREATED="tauri://window-created",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_FILE_DROP="tauri://file-drop",e.WINDOW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WINDOW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled",e.MENU="tauri://menu",e))(d||{});async function E(e,n){await l("plugin:event|unlisten",{event:e,eventId:n})}async function h(e,n,t){return l("plugin:event|listen",{event:e,windowLabel:t?.target,handler:a(n)}).then((n=>async()=>E(e,n)))}async function I(e,n,t){return h(e,(t=>{n(t),E(e,t.id).catch((()=>{}))}),t)}async function v(e,n,t){await l("plugin:event|emit",{event:e,windowLabel:t?.target,payload:n})}async function N(){return await l("plugin:deep-link|get_current")}return e.getCurrent=N,e.onOpenUrl=async function(e){const n=await N();return null!=n&&e(n),await h("deep-link://new-url",(n=>e(n.payload)))},e}({});Object.defineProperty(window.__TAURI__,"deepLink",{value:__TAURI_DEEPLINK__})}
|
if("__TAURI__"in window){var __TAURI_DEEPLINK__=function(e){"use strict";function n(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}async function r(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}var t;async function _(e,t,_){return r("plugin:event|listen",{event:e,windowLabel:_?.target,handler:n(t)}).then((n=>async()=>async function(e,n){await r("plugin:event|unlisten",{event:e,eventId:n})}(e,n)))}async function i(){return await r("plugin:deep-link|get_current")}return"function"==typeof SuppressedError&&SuppressedError,function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_CREATED="tauri://window-created",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_FILE_DROP="tauri://file-drop",e.WINDOW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WINDOW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled",e.MENU="tauri://menu"}(t||(t={})),e.getCurrent=i,e.onOpenUrl=async function(e){const n=await i();return null!=n&&e(n),await _("deep-link://new-url",(n=>e(n.payload)))},e}({});Object.defineProperty(window.__TAURI__,"deepLink",{value:__TAURI_DEEPLINK__})}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> {
|
|||||||
.on_event(|_app, _event| {
|
.on_event(|_app, _event| {
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
if let tauri::RunEvent::Opened { urls } = _event {
|
if let tauri::RunEvent::Opened { urls } = _event {
|
||||||
let _ = _app.emit_all("deep-link://new-url", urls);
|
let _ = _app.emit("deep-link://new-url", urls);
|
||||||
_app.state::<DeepLink<R>>()
|
_app.state::<DeepLink<R>>()
|
||||||
.current
|
.current
|
||||||
.lock()
|
.lock()
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
@@ -29,8 +33,9 @@
|
|||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
`
|
\`
|
||||||
|
|
||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
|
pull/371)) First v2 alpha release!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-dialog"
|
name = "tauri-plugin-dialog"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
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,7 +9,8 @@ rust-version = { workspace = true }
|
|||||||
links = "tauri-plugin-dialog"
|
links = "tauri-plugin-dialog"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "dox" ]
|
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" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -18,17 +19,14 @@ serde_json = { workspace = true }
|
|||||||
tauri = { workspace = true }
|
tauri = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tauri-plugin-fs = { path = "../fs", version = "2.0.0-alpha.3" }
|
tauri-plugin-fs = { path = "../fs", version = "2.0.0-alpha.4" }
|
||||||
|
|
||||||
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
|
||||||
glib = "0.16"
|
glib = "0.16"
|
||||||
|
|
||||||
[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.11", features = [ "gtk3", "common-controls-v6" ] }
|
rfd = { version = "0.12", features = [ "gtk3", "common-controls-v6" ] }
|
||||||
raw-window-handle = "0.5"
|
raw-window-handle = "0.5"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { workspace = true }
|
tauri-build = { workspace = true }
|
||||||
|
|
||||||
[features]
|
|
||||||
dox = [ "tauri/dox" ]
|
|
||||||
|
|||||||
@@ -14,24 +14,44 @@ import androidx.activity.result.ActivityResult
|
|||||||
import app.tauri.Logger
|
import app.tauri.Logger
|
||||||
import app.tauri.annotation.ActivityCallback
|
import app.tauri.annotation.ActivityCallback
|
||||||
import app.tauri.annotation.Command
|
import app.tauri.annotation.Command
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.annotation.TauriPlugin
|
import app.tauri.annotation.TauriPlugin
|
||||||
import app.tauri.plugin.Invoke
|
import app.tauri.plugin.Invoke
|
||||||
import app.tauri.plugin.JSArray
|
import app.tauri.plugin.JSArray
|
||||||
import app.tauri.plugin.JSObject
|
import app.tauri.plugin.JSObject
|
||||||
import app.tauri.plugin.Plugin
|
import app.tauri.plugin.Plugin
|
||||||
import org.json.JSONException
|
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class Filter {
|
||||||
|
lateinit var extensions: Array<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class FilePickerOptions {
|
||||||
|
lateinit var filters: Array<Filter>
|
||||||
|
var multiple: Boolean? = null
|
||||||
|
var readData: Boolean? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class MessageOptions {
|
||||||
|
var title: String? = null
|
||||||
|
lateinit var message: String
|
||||||
|
var okButtonLabel: String? = null
|
||||||
|
var cancelButtonLabel: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
@TauriPlugin
|
@TauriPlugin
|
||||||
class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||||
|
var filePickerOptions: FilePickerOptions? = null
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun showFilePicker(invoke: Invoke) {
|
fun showFilePicker(invoke: Invoke) {
|
||||||
try {
|
try {
|
||||||
val filters = invoke.getArray("filters", JSArray())
|
val args = invoke.parseArgs(FilePickerOptions::class.java)
|
||||||
val multiple = invoke.getBoolean("multiple", false)
|
val parsedTypes = parseFiltersOption(args.filters)
|
||||||
val parsedTypes = parseFiltersOption(filters)
|
|
||||||
|
|
||||||
val intent = if (parsedTypes != null && parsedTypes.isNotEmpty()) {
|
val intent = if (parsedTypes.isNotEmpty()) {
|
||||||
val intent = Intent(Intent.ACTION_PICK)
|
val intent = Intent(Intent.ACTION_PICK)
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
|
||||||
|
|
||||||
@@ -55,7 +75,7 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
intent
|
intent
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple)
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, args.multiple ?: false)
|
||||||
|
|
||||||
startActivityForResult(invoke, intent, "filePickerResult")
|
startActivityForResult(invoke, intent, "filePickerResult")
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
@@ -68,10 +88,9 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
@ActivityCallback
|
@ActivityCallback
|
||||||
fun filePickerResult(invoke: Invoke, result: ActivityResult) {
|
fun filePickerResult(invoke: Invoke, result: ActivityResult) {
|
||||||
try {
|
try {
|
||||||
val readData = invoke.getBoolean("readData", false)
|
|
||||||
when (result.resultCode) {
|
when (result.resultCode) {
|
||||||
Activity.RESULT_OK -> {
|
Activity.RESULT_OK -> {
|
||||||
val callResult = createPickFilesResult(result.data, readData)
|
val callResult = createPickFilesResult(result.data, filePickerOptions?.readData ?: false)
|
||||||
invoke.resolve(callResult)
|
invoke.resolve(callResult)
|
||||||
}
|
}
|
||||||
Activity.RESULT_CANCELED -> invoke.reject("File picker cancelled")
|
Activity.RESULT_CANCELED -> invoke.reject("File picker cancelled")
|
||||||
@@ -130,36 +149,19 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
return callResult
|
return callResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseFiltersOption(filters: JSArray): Array<String>? {
|
private fun parseFiltersOption(filters: Array<Filter>): Array<String> {
|
||||||
return try {
|
|
||||||
val filtersList: List<JSObject> = filters.toList()
|
|
||||||
val mimeTypes = mutableListOf<String>()
|
val mimeTypes = mutableListOf<String>()
|
||||||
for (filter in filtersList) {
|
for (filter in filters) {
|
||||||
val extensionsList = filter.getJSONArray("extensions")
|
for (mime in filter.extensions) {
|
||||||
for (i in 0 until extensionsList.length()) {
|
|
||||||
val mime = extensionsList.getString(i)
|
|
||||||
mimeTypes.add(if (mime == "text/csv") "text/comma-separated-values" else mime)
|
mimeTypes.add(if (mime == "text/csv") "text/comma-separated-values" else mime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return mimeTypes.toTypedArray()
|
||||||
mimeTypes.toTypedArray()
|
|
||||||
} catch (exception: JSONException) {
|
|
||||||
Logger.error("parseTypesOption failed.", exception)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun showMessageDialog(invoke: Invoke) {
|
fun showMessageDialog(invoke: Invoke) {
|
||||||
val title = invoke.getString("title")
|
val args = invoke.parseArgs(MessageOptions::class.java)
|
||||||
val message = invoke.getString("message")
|
|
||||||
val okButtonLabel = invoke.getString("okButtonLabel", "OK")
|
|
||||||
val cancelButtonLabel = invoke.getString("cancelButtonLabel", "Cancel")
|
|
||||||
|
|
||||||
if (message == null) {
|
|
||||||
invoke.reject("The `message` argument is required")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activity.isFinishing) {
|
if (activity.isFinishing) {
|
||||||
invoke.reject("App is finishing")
|
invoke.reject("App is finishing")
|
||||||
@@ -177,19 +179,19 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
.post {
|
.post {
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
|
|
||||||
if (title != null) {
|
if (args.title != null) {
|
||||||
builder.setTitle(title)
|
builder.setTitle(args.title)
|
||||||
}
|
}
|
||||||
builder
|
builder
|
||||||
.setMessage(message)
|
.setMessage(args.message)
|
||||||
.setPositiveButton(
|
.setPositiveButton(
|
||||||
okButtonLabel
|
args.okButtonLabel ?: "OK"
|
||||||
) { dialog, _ ->
|
) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
handler(false, true)
|
handler(false, true)
|
||||||
}
|
}
|
||||||
.setNegativeButton(
|
.setNegativeButton(
|
||||||
cancelButtonLabel
|
args.cancelButtonLabel ?: "Cancel"
|
||||||
) { dialog, _ ->
|
) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
handler(false, false)
|
handler(false, false)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fn main() {
|
|||||||
{
|
{
|
||||||
println!("{error:#}");
|
println!("{error:#}");
|
||||||
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
||||||
if !(cfg!(feature = "dox") && std::env::var("TARGET").unwrap().contains("android")) {
|
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
import PhotosUI
|
|
||||||
import Photos
|
import Photos
|
||||||
import WebKit
|
import PhotosUI
|
||||||
import Tauri
|
|
||||||
import SwiftRs
|
import SwiftRs
|
||||||
|
import Tauri
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
enum FilePickerEvent {
|
enum FilePickerEvent {
|
||||||
case selected([URL])
|
case selected([URL])
|
||||||
@@ -16,20 +16,38 @@ enum FilePickerEvent {
|
|||||||
case error(String)
|
case error(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MessageDialogOptions: Decodable {
|
||||||
|
let title: String?
|
||||||
|
let message: String
|
||||||
|
var okButtonLabel = "OK"
|
||||||
|
var cancelButtonLabel = "Cancel"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Filter: Decodable {
|
||||||
|
var extensions: [String] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FilePickerOptions: Decodable {
|
||||||
|
var multiple = false
|
||||||
|
var readData = false
|
||||||
|
var filters: [Filter] = []
|
||||||
|
}
|
||||||
|
|
||||||
class DialogPlugin: Plugin {
|
class DialogPlugin: Plugin {
|
||||||
|
|
||||||
var filePickerController: FilePickerController!
|
var filePickerController: FilePickerController!
|
||||||
var pendingInvoke: Invoke? = nil
|
var pendingInvoke: Invoke? = nil
|
||||||
|
var pendingInvokeArgs: FilePickerOptions? = nil
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
filePickerController = FilePickerController(self)
|
filePickerController = FilePickerController(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func showFilePicker(_ invoke: Invoke) {
|
@objc public func showFilePicker(_ invoke: Invoke) throws {
|
||||||
let multiple = invoke.getBool("multiple", false)
|
let args = try invoke.parseArgs(FilePickerOptions.self)
|
||||||
let filters = invoke.getArray("filters") ?? []
|
|
||||||
let parsedTypes = parseFiltersOption(filters)
|
let parsedTypes = parseFiltersOption(args.filters)
|
||||||
|
|
||||||
var isMedia = true
|
var isMedia = true
|
||||||
var uniqueMimeType: Bool? = nil
|
var uniqueMimeType: Bool? = nil
|
||||||
@@ -41,21 +59,22 @@ class DialogPlugin: Plugin {
|
|||||||
if kind != "image" && kind != "video" {
|
if kind != "image" && kind != "video" {
|
||||||
isMedia = false
|
isMedia = false
|
||||||
}
|
}
|
||||||
if (mimeKind == nil) {
|
if mimeKind == nil {
|
||||||
mimeKind = kind
|
mimeKind = kind
|
||||||
} else if (mimeKind != kind) {
|
} else if mimeKind != kind {
|
||||||
uniqueMimeType = false
|
uniqueMimeType = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingInvoke = invoke
|
pendingInvoke = invoke
|
||||||
|
pendingInvokeArgs = args
|
||||||
|
|
||||||
if uniqueMimeType == true || isMedia {
|
if uniqueMimeType == true || isMedia {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if #available(iOS 14, *) {
|
if #available(iOS 14, *) {
|
||||||
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
||||||
configuration.selectionLimit = multiple ? 0 : 1
|
configuration.selectionLimit = args.multiple ? 0 : 1
|
||||||
|
|
||||||
if uniqueMimeType == true {
|
if uniqueMimeType == true {
|
||||||
if mimeKind == "image" {
|
if mimeKind == "image" {
|
||||||
@@ -87,7 +106,7 @@ class DialogPlugin: Plugin {
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
|
let picker = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
|
||||||
picker.delegate = self.filePickerController
|
picker.delegate = self.filePickerController
|
||||||
picker.allowsMultipleSelection = multiple
|
picker.allowsMultipleSelection = args.multiple
|
||||||
picker.modalPresentationStyle = .fullScreen
|
picker.modalPresentationStyle = .fullScreen
|
||||||
self.presentViewController(picker)
|
self.presentViewController(picker)
|
||||||
}
|
}
|
||||||
@@ -98,32 +117,28 @@ class DialogPlugin: Plugin {
|
|||||||
self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
|
self.manager.viewController?.present(viewControllerToPresent, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func parseFiltersOption(_ filters: JSArray) -> [String] {
|
private func parseFiltersOption(_ filters: [Filter]) -> [String] {
|
||||||
var parsedTypes: [String] = []
|
var parsedTypes: [String] = []
|
||||||
for (_, filter) in filters.enumerated() {
|
for filter in filters {
|
||||||
let filterObj = filter as? JSObject
|
for ext in filter.extensions {
|
||||||
if let filterObj = filterObj {
|
guard
|
||||||
let extensions = filterObj["extensions"] as? JSArray
|
let utType: String = UTTypeCreatePreferredIdentifierForTag(
|
||||||
if let extensions = extensions {
|
kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String?
|
||||||
for e in extensions {
|
else {
|
||||||
let ext = e as? String ?? ""
|
|
||||||
guard let utType: String = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, ext as CFString, nil)?.takeRetainedValue() as String? else {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parsedTypes.append(utType)
|
parsedTypes.append(utType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return parsedTypes
|
return parsedTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onFilePickerEvent(_ event: FilePickerEvent) {
|
public func onFilePickerEvent(_ event: FilePickerEvent) {
|
||||||
switch event {
|
switch event {
|
||||||
case .selected(let urls):
|
case .selected(let urls):
|
||||||
let readData = pendingInvoke?.getBool("readData", false) ?? false
|
let readData = pendingInvokeArgs?.readData ?? false
|
||||||
do {
|
do {
|
||||||
let filesResult = try urls.map {(url: URL) -> JSObject in
|
let filesResult = try urls.map { (url: URL) -> JSObject in
|
||||||
var file = JSObject()
|
var file = JSObject()
|
||||||
|
|
||||||
let mimeType = filePickerController.getMimeTypeFromUrl(url)
|
let mimeType = filePickerController.getMimeTypeFromUrl(url)
|
||||||
@@ -162,7 +177,7 @@ class DialogPlugin: Plugin {
|
|||||||
}
|
}
|
||||||
pendingInvoke?.resolve(["files": filesResult])
|
pendingInvoke?.resolve(["files": filesResult])
|
||||||
} catch let error as NSError {
|
} catch let error as NSError {
|
||||||
pendingInvoke?.reject(error.localizedDescription, nil, error)
|
pendingInvoke?.reject(error.localizedDescription, error: error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,28 +190,29 @@ class DialogPlugin: Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func showMessageDialog(_ invoke: Invoke) {
|
@objc public func showMessageDialog(_ invoke: Invoke) throws {
|
||||||
let manager = self.manager
|
let manager = self.manager
|
||||||
let title = invoke.getString("title")
|
let args = try invoke.parseArgs(MessageDialogOptions.self)
|
||||||
guard let message = invoke.getString("message") else {
|
|
||||||
invoke.reject("The `message` argument is required")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let okButtonLabel = invoke.getString("okButtonLabel") ?? "OK"
|
|
||||||
let cancelButtonLabel = invoke.getString("cancelButtonLabel") ?? "Cancel"
|
|
||||||
|
|
||||||
DispatchQueue.main.async { [] in
|
DispatchQueue.main.async { [] in
|
||||||
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
|
let alert = UIAlertController(
|
||||||
alert.addAction(UIAlertAction(title: cancelButtonLabel, style: UIAlertAction.Style.default, handler: { (_) -> Void in
|
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
|
||||||
|
alert.addAction(
|
||||||
|
UIAlertAction(
|
||||||
|
title: args.cancelButtonLabel, style: UIAlertAction.Style.default,
|
||||||
|
handler: { (_) -> Void in
|
||||||
invoke.resolve([
|
invoke.resolve([
|
||||||
"value": false,
|
"value": false,
|
||||||
"cancelled": false
|
"cancelled": false,
|
||||||
])
|
])
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: okButtonLabel, style: UIAlertAction.Style.default, handler: { (_) -> Void in
|
alert.addAction(
|
||||||
|
UIAlertAction(
|
||||||
|
title: args.okButtonLabel, style: UIAlertAction.Style.default,
|
||||||
|
handler: { (_) -> Void in
|
||||||
invoke.resolve([
|
invoke.resolve([
|
||||||
"value": true,
|
"value": true,
|
||||||
"cancelled": false
|
"cancelled": false,
|
||||||
])
|
])
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-dialog",
|
"name": "@tauri-apps/plugin-dialog",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "^2.4.1"
|
"tslib": "^2.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_DIALOG__=function(n){"use strict";var t=Object.defineProperty,e=(n,t,e)=>{if(!t.has(n))throw TypeError("Cannot "+e)},i=(n,t,i)=>(e(n,t,"read from private field"),i?i.call(n):t.get(n));function o(n,t=!1){return window.__TAURI_INTERNALS__.transformCallback(n,t)}((n,e)=>{for(var i in e)t(n,i,{get:e[i],enumerable:!0})})({},{Channel:()=>r,PluginListener:()=>a,addPluginListener:()=>s,convertFileSrc:()=>d,invoke:()=>u,transformCallback:()=>o});var l,r=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((n,t,e)=>{if(t.has(n))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(n):t.set(n,e)})(this,l,(()=>{})),this.id=o((n=>{i(this,l).call(this,n)}))}set onmessage(n){var t,i,o,r;o=n,e(t=this,i=l,"write to private field"),r?r.call(t,o):i.set(t,o)}get onmessage(){return i(this,l)}toJSON(){return`__CHANNEL__:${this.id}`}};l=new WeakMap;var a=class{constructor(n,t,e){this.plugin=n,this.event=t,this.channelId=e}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function s(n,t,e){let i=new r;return i.onmessage=e,u(`plugin:${n}|register_listener`,{event:t,handler:i}).then((()=>new a(n,t,i.id)))}async function u(n,t={},e){return window.__TAURI_INTERNALS__.invoke(n,t,e)}function d(n,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(n,t)}return n.ask=async function(n,t){var e,i,o,l,r;const a="string"==typeof t?{title:t}:t;return u("plugin:dialog|ask",{message:n.toString(),title:null===(e=null==a?void 0:a.title)||void 0===e?void 0:e.toString(),type_:null==a?void 0:a.type,okButtonLabel:null!==(o=null===(i=null==a?void 0:a.okLabel)||void 0===i?void 0:i.toString())&&void 0!==o?o:"Yes",cancelButtonLabel:null!==(r=null===(l=null==a?void 0:a.cancelLabel)||void 0===l?void 0:l.toString())&&void 0!==r?r:"No"})},n.confirm=async function(n,t){var e,i,o,l,r;const a="string"==typeof t?{title:t}:t;return u("plugin:dialog|confirm",{message:n.toString(),title:null===(e=null==a?void 0:a.title)||void 0===e?void 0:e.toString(),type_:null==a?void 0:a.type,okButtonLabel:null!==(o=null===(i=null==a?void 0:a.okLabel)||void 0===i?void 0:i.toString())&&void 0!==o?o:"Ok",cancelButtonLabel:null!==(r=null===(l=null==a?void 0:a.cancelLabel)||void 0===l?void 0:l.toString())&&void 0!==r?r:"Cancel"})},n.message=async function(n,t){var e,i;const o="string"==typeof t?{title:t}:t;return u("plugin:dialog|message",{message:n.toString(),title:null===(e=null==o?void 0:o.title)||void 0===e?void 0:e.toString(),type_:null==o?void 0:o.type,okButtonLabel:null===(i=null==o?void 0:o.okLabel)||void 0===i?void 0:i.toString()})},n.open=async function(n={}){return"object"==typeof n&&Object.freeze(n),u("plugin:dialog|open",{options:n})},n.save=async function(n={}){return"object"==typeof n&&Object.freeze(n),u("plugin:dialog|save",{options:n})},n}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_DIALOG__})}
|
if("__TAURI__"in window){var __TAURI_DIALOG__=function(n){"use strict";async function o(n,o={},t){return window.__TAURI_INTERNALS__.invoke(n,o,t)}return"function"==typeof SuppressedError&&SuppressedError,n.ask=async function(n,t){var i,l,e,u,r;const d="string"==typeof t?{title:t}:t;return o("plugin:dialog|ask",{message:n.toString(),title:null===(i=null==d?void 0:d.title)||void 0===i?void 0:i.toString(),type_:null==d?void 0:d.type,okButtonLabel:null!==(e=null===(l=null==d?void 0:d.okLabel)||void 0===l?void 0:l.toString())&&void 0!==e?e:"Yes",cancelButtonLabel:null!==(r=null===(u=null==d?void 0:d.cancelLabel)||void 0===u?void 0:u.toString())&&void 0!==r?r:"No"})},n.confirm=async function(n,t){var i,l,e,u,r;const d="string"==typeof t?{title:t}:t;return o("plugin:dialog|confirm",{message:n.toString(),title:null===(i=null==d?void 0:d.title)||void 0===i?void 0:i.toString(),type_:null==d?void 0:d.type,okButtonLabel:null!==(e=null===(l=null==d?void 0:d.okLabel)||void 0===l?void 0:l.toString())&&void 0!==e?e:"Ok",cancelButtonLabel:null!==(r=null===(u=null==d?void 0:d.cancelLabel)||void 0===u?void 0:u.toString())&&void 0!==r?r:"Cancel"})},n.message=async function(n,t){var i,l;const e="string"==typeof t?{title:t}:t;return o("plugin:dialog|message",{message:n.toString(),title:null===(i=null==e?void 0:e.title)||void 0===i?void 0:i.toString(),type_:null==e?void 0:e.type,okButtonLabel:null===(l=null==e?void 0:e.okLabel)||void 0===l?void 0:l.toString()})},n.open=async function(n={}){return"object"==typeof n&&Object.freeze(n),o("plugin:dialog|open",{options:n})},n.save=async function(n={}){return"object"==typeof n&&Object.freeze(n),o("plugin:dialog|save",{options:n})},n}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_DIALOG__})}
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ macro_rules! run_dialog {
|
|||||||
($e:expr, $h: ident) => {{
|
($e:expr, $h: ident) => {{
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let response = tauri::async_runtime::block_on($e);
|
let response = tauri::async_runtime::block_on($e);
|
||||||
$h(response);
|
$h(!matches!(
|
||||||
|
response,
|
||||||
|
rfd::MessageDialogResult::No | rfd::MessageDialogResult::Cancel
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@@ -68,7 +71,10 @@ macro_rules! run_dialog {
|
|||||||
let context = glib::MainContext::default();
|
let context = glib::MainContext::default();
|
||||||
context.invoke_with_priority(glib::PRIORITY_HIGH, move || {
|
context.invoke_with_priority(glib::PRIORITY_HIGH, move || {
|
||||||
let response = $e;
|
let response = $e;
|
||||||
$h(response);
|
$h(!matches!(
|
||||||
|
response,
|
||||||
|
rfd::MessageDialogResult::No | rfd::MessageDialogResult::Cancel
|
||||||
|
));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}};
|
}};
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
!function(){"use strict";var e=Object.defineProperty,n=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},t=(e,t,r)=>(n(e,t,"read from private field"),r?r.call(e):t.get(e));function r(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}((n,t)=>{for(var r in t)e(n,r,{get:t[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>a,addPluginListener:()=>o,convertFileSrc:()=>c,invoke:()=>l,transformCallback:()=>r});var i,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,i,(()=>{})),this.id=r((e=>{t(this,i).call(this,e)}))}set onmessage(e){var t,r,s,a;s=e,n(t=this,r=i,"write to private field"),a?a.call(t,s):r.set(t,s)}get onmessage(){return t(this,i)}toJSON(){return`__CHANNEL__:${this.id}`}};i=new WeakMap;var a=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return l(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function o(e,n,t){let r=new s;return r.onmessage=t,l(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new a(e,n,r.id)))}async function l(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function c(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}window.alert=function(e){l("plugin:dialog|message",{message:e.toString()})},window.confirm=function(e){return l("plugin:dialog|confirm",{message:e.toString()})}}();
|
!function(){"use strict";async function n(n,i={},o){return window.__TAURI_INTERNALS__.invoke(n,i,o)}"function"==typeof SuppressedError&&SuppressedError,window.alert=function(i){n("plugin:dialog|message",{message:i.toString()})},window.confirm=function(i){return n("plugin:dialog|confirm",{message:i.toString()})}}();
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-fs"
|
name = "tauri-plugin-fs"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
description = "Access the file system."
|
description = "Access the file system."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-fs",
|
"name": "@tauri-apps/plugin-fs",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"description": "Access the file system.",
|
"description": "Access the file system.",
|
||||||
"license": "MIT or APACHE-2.0",
|
"license": "MIT or APACHE-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
"tslib": "^2.4.1"
|
"tslib": "^2.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
@@ -20,7 +24,7 @@
|
|||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
\-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
te to alpha.11.
|
te to alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-global-shortcut"
|
name = "tauri-plugin-global-shortcut"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
description = "Register global hotkeys listeners on your Tauri application."
|
description = "Register global hotkeys listeners on your Tauri application."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -8,7 +8,8 @@ license = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-global-shortcut",
|
"name": "@tauri-apps/plugin-global-shortcut",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "^2.4.1"
|
"tslib": "^2.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_GLOBALSHORTCUT__=function(e){"use strict";var t=Object.defineProperty,n=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)},r=(e,t,r)=>(n(e,t,"read from private field"),r?r.call(e):t.get(e));function i(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((e,n)=>{for(var r in n)t(e,r,{get:n[r],enumerable:!0})})({},{Channel:()=>a,PluginListener:()=>o,addPluginListener:()=>l,convertFileSrc:()=>c,invoke:()=>u,transformCallback:()=>i});var s,a=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,t,n)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)})(this,s,(()=>{})),this.id=i((e=>{r(this,s).call(this,e)}))}set onmessage(e){var t,r,i,a;i=e,n(t=this,r=s,"write to private field"),a?a.call(t,i):r.set(t,i)}get onmessage(){return r(this,s)}toJSON(){return`__CHANNEL__:${this.id}`}};s=new WeakMap;var o=class{constructor(e,t,n){this.plugin=e,this.event=t,this.channelId=n}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function l(e,t,n){let r=new a;return r.onmessage=n,u(`plugin:${e}|register_listener`,{event:t,handler:r}).then((()=>new o(e,t,r.id)))}async function u(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}function c(e,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,t)}return e.isRegistered=async function(e){return await u("plugin:globalShortcut|is_registered",{shortcut:e})},e.register=async function(e,t){const n=new a;return n.onmessage=t,await u("plugin:globalShortcut|register",{shortcut:e,handler:n})},e.registerAll=async function(e,t){const n=new a;return n.onmessage=t,await u("plugin:globalShortcut|register_all",{shortcuts:e,handler:n})},e.unregister=async function(e){return await u("plugin:globalShortcut|unregister",{shortcut:e})},e.unregisterAll=async function(){return await u("plugin:globalShortcut|unregister_all")},e}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_GLOBALSHORTCUT__})}
|
if("__TAURI__"in window){var __TAURI_GLOBALSHORTCUT__=function(t){"use strict";function e(t,e,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!n:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(t):n?n.value:e.get(t)}var r;"function"==typeof SuppressedError&&SuppressedError;class n{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,r.set(this,(()=>{})),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((t=>{e(this,r,"f").call(this,t)}))}set onmessage(t){!function(t,e,r,n,o){if("m"===n)throw new TypeError("Private method is not writable");if("a"===n&&!o)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof e?t!==e||!o:!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");"a"===n?o.call(t,r):o?o.value=r:e.set(t,r)}(this,r,t,"f")}get onmessage(){return e(this,r,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}async function o(t,e={},r){return window.__TAURI_INTERNALS__.invoke(t,e,r)}return r=new WeakMap,t.isRegistered=async function(t){return await o("plugin:globalShortcut|is_registered",{shortcut:t})},t.register=async function(t,e){const r=new n;return r.onmessage=e,await o("plugin:globalShortcut|register",{shortcut:t,handler:r})},t.registerAll=async function(t,e){const r=new n;return r.onmessage=e,await o("plugin:globalShortcut|register_all",{shortcuts:t,handler:r})},t.unregister=async function(t){return await o("plugin:globalShortcut|unregister",{shortcut:t})},t.unregisterAll=async function(){return await o("plugin:globalShortcut|unregister_all")},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_GLOBALSHORTCUT__})}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.3]
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
@@ -26,4 +30,6 @@
|
|||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
371)) First v2 alpha release!
|
371\)) First v2 alpha release!
|
||||||
|
!
|
||||||
|
371\)) First v2 alpha release!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-http"
|
name = "tauri-plugin-http"
|
||||||
version = "2.0.0-alpha.4"
|
version = "2.0.0-alpha.5"
|
||||||
description = "Access an HTTP client written in Rust."
|
description = "Access an HTTP client written in Rust."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -8,14 +8,15 @@ license = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tauri = { workspace = true }
|
tauri = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tauri-plugin-fs = { path = "../fs", version = "2.0.0-alpha.3" }
|
tauri-plugin-fs = { path = "../fs", version = "2.0.0-alpha.4" }
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
reqwest = { version = "0.11", default-features = false }
|
reqwest = { version = "0.11", default-features = false }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-http",
|
"name": "@tauri-apps/plugin-http",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"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"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_HTTP__=function(e){"use strict";var t=Object.defineProperty,n=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)},r=(e,t,r)=>(n(e,t,"read from private field"),r?r.call(e):t.get(e));function i(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((e,n)=>{for(var r in n)t(e,r,{get:n[r],enumerable:!0})})({},{Channel:()=>s,PluginListener:()=>o,addPluginListener:()=>c,convertFileSrc:()=>_,invoke:()=>l,transformCallback:()=>i});var a,s=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,t,n)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)})(this,a,(()=>{})),this.id=i((e=>{r(this,a).call(this,e)}))}set onmessage(e){var t,r,i,s;i=e,n(t=this,r=a,"write to private field"),s?s.call(t,i):r.set(t,i)}get onmessage(){return r(this,a)}toJSON(){return`__CHANNEL__:${this.id}`}};a=new WeakMap;var o=class{constructor(e,t,n){this.plugin=e,this.event=t,this.channelId=n}async unregister(){return l(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function c(e,t,n){let r=new s;return r.onmessage=n,l(`plugin:${e}|register_listener`,{event:t,handler:r}).then((()=>new o(e,t,r.id)))}async function l(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}function _(e,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,t)}return e.fetch=async function(e,t){const n=null==t?void 0:t.maxRedirections,r=null==t?void 0:t.maxRedirections;t&&(delete t.maxRedirections,delete t.connectTimeout);const i=new Request(e,t),a=await i.arrayBuffer(),s=a.byteLength?Array.from(new Uint8Array(a)):null,o=await l("plugin:http|fetch",{method:i.method,url:i.url,headers:Array.from(i.headers.entries()),data:s,maxRedirections:n,connectTimeout:r});i.signal.addEventListener("abort",(()=>{l("plugin:http|fetch_cancel",{rid:o})}));const{status:c,statusText:_,url:d,headers:u}=await l("plugin:http|fetch_send",{rid:o}),h=await l("plugin:http|fetch_read_body",{rid:o}),f=new Response(new Uint8Array(h),{headers:u,status:c,statusText:_});return Object.defineProperty(f,"url",{value:d}),f},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_HTTP__})}
|
if("__TAURI__"in window){var __TAURI_HTTP__=function(e){"use strict";async function t(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}return"function"==typeof SuppressedError&&SuppressedError,e.fetch=async function(e,n){const r=null==n?void 0:n.maxRedirections,i=null==n?void 0:n.maxRedirections;n&&(delete n.maxRedirections,delete n.connectTimeout);const a=new Request(e,n),s=await a.arrayBuffer(),o=s.byteLength?Array.from(new Uint8Array(s)):null,u=await t("plugin:http|fetch",{method:a.method,url:a.url,headers:Array.from(a.headers.entries()),data:o,maxRedirections:r,connectTimeout:i});a.signal.addEventListener("abort",(()=>{t("plugin:http|fetch_cancel",{rid:u})}));const{status:d,statusText:c,url:_,headers:l}=await t("plugin:http|fetch_send",{rid:u}),f=await t("plugin:http|fetch_read_body",{rid:u}),h=new Response(new Uint8Array(f),{headers:l,status:d,statusText:c});return Object.defineProperty(h,"url",{value:_}),h},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_HTTP__})}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.4]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to tauri@alpha.17.
|
||||||
|
|
||||||
## \[2.0.0-alpha.3]
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update MSRV to 1.70.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update MSRV to 1.70.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-localhost"
|
name = "tauri-plugin-localhost"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
description = "Expose your apps assets through a localhost server instead of the default custom protocol."
|
description = "Expose your apps assets through a localhost server instead of the default custom protocol."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
@@ -20,4 +24,6 @@
|
|||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
|
v2 alpha release!
|
||||||
|
https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-log"
|
name = "tauri-plugin-log"
|
||||||
version = "2.0.0-alpha.3"
|
version = "2.0.0-alpha.4"
|
||||||
description = "Configurable logging for your Tauri app."
|
description = "Configurable logging for your Tauri app."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||||||
rust-version = { workspace = true }
|
rust-version = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "tauri/dox" ]
|
rustc-args = [ "--cfg", "docsrs" ]
|
||||||
|
rustdoc-args = [ "--cfg", "docsrs" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { workspace = true }
|
tauri-build = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-log",
|
"name": "@tauri-apps/plugin-log",
|
||||||
"version": "2.0.0-alpha.2",
|
"version": "2.0.0-alpha.3",
|
||||||
"description": "Configurable logging for your Tauri app.",
|
"description": "Configurable logging for your Tauri app.",
|
||||||
"license": "MIT or APACHE-2.0",
|
"license": "MIT or APACHE-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -28,6 +28,6 @@
|
|||||||
"tslib": "2.6.0"
|
"tslib": "2.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.0.0-alpha.9"
|
"@tauri-apps/api": "2.0.0-alpha.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_LOG__=function(e){"use strict";var n=Object.defineProperty,t=(e,t)=>{for(var r in t)n(e,r,{get:t[r],enumerable:!0})},r=(e,n,t)=>{if(!n.has(e))throw TypeError("Cannot "+t)},a=(e,n,t)=>(r(e,n,"read from private field"),t?t.call(e):n.get(e));function i(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}t({},{Channel:()=>l,PluginListener:()=>s,addPluginListener:()=>c,convertFileSrc:()=>_,invoke:()=>u,transformCallback:()=>i});var o,l=class{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,((e,n,t)=>{if(n.has(e))throw TypeError("Cannot add the same private member more than once");n instanceof WeakSet?n.add(e):n.set(e,t)})(this,o,(()=>{})),this.id=i((e=>{a(this,o).call(this,e)}))}set onmessage(e){((e,n,t,a)=>{r(e,n,"write to private field"),a?a.call(e,t):n.set(e,t)})(this,o,e)}get onmessage(){return a(this,o)}toJSON(){return`__CHANNEL__:${this.id}`}};o=new WeakMap;var s=class{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}};async function c(e,n,t){let r=new l;return r.onmessage=t,u(`plugin:${e}|register_listener`,{event:n,handler:r}).then((()=>new s(e,n,r.id)))}async function u(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}function _(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)}t({},{TauriEvent:()=>f,emit:()=>E,listen:()=>w,once:()=>g});var d,f=(e=>(e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_CREATED="tauri://window-created",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_FILE_DROP="tauri://file-drop",e.WINDOW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WINDOW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled",e.MENU="tauri://menu",e))(f||{});async function v(e,n){await u("plugin:event|unlisten",{event:e,eventId:n})}async function w(e,n,t){return u("plugin:event|listen",{event:e,windowLabel:t?.target,handler:i(n)}).then((n=>async()=>v(e,n)))}async function g(e,n,t){return w(e,(t=>{n(t),v(e,t.id).catch((()=>{}))}),t)}async function E(e,n,t){await u("plugin:event|emit",{event:e,windowLabel:t?.target,payload:n})}async function h(e,n,t){var r,a;const i=null===(r=(new Error).stack)||void 0===r?void 0:r.split("\n").map((e=>e.split("@"))),o=null==i?void 0:i.filter((([e,n])=>e.length>0&&"[native code]"!==n)),{file:l,line:s,keyValues:c}=null!=t?t:{};let _=null===(a=null==o?void 0:o[0])||void 0===a?void 0:a.filter((e=>e.length>0)).join("@");"Error"===_&&(_="webview::unknown"),await u("plugin:log|log",{level:e,message:n,location:_,file:l,line:s,keyValues:c})}return function(e){e[e.Trace=1]="Trace",e[e.Debug=2]="Debug",e[e.Info=3]="Info",e[e.Warn=4]="Warn",e[e.Error=5]="Error"}(d||(d={})),e.attachConsole=async function(){return await w("log://log",(e=>{const n=e.payload,t=n.message.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,"");switch(n.level){case d.Trace:console.log(t);break;case d.Debug:console.debug(t);break;case d.Info:console.info(t);break;case d.Warn:console.warn(t);break;case d.Error:console.error(t);break;default:throw new Error(`unknown log level ${n.level}`)}}))},e.debug=async function(e,n){await h(d.Debug,e,n)},e.error=async function(e,n){await h(d.Error,e,n)},e.info=async function(e,n){await h(d.Info,e,n)},e.trace=async function(e,n){await h(d.Trace,e,n)},e.warn=async function(e,n){await h(d.Warn,e,n)},e}({});Object.defineProperty(window.__TAURI__,"log",{value:__TAURI_LOG__})}
|
if("__TAURI__"in window){var __TAURI_LOG__=function(e){"use strict";function n(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}async function r(e,n={},r){return window.__TAURI_INTERNALS__.invoke(e,n,r)}var a,o;async function t(e,a,o){return r("plugin:event|listen",{event:e,windowLabel:o?.target,handler:n(a)}).then((n=>async()=>async function(e,n){await r("plugin:event|unlisten",{event:e,eventId:n})}(e,n)))}async function i(e,n,a){var o,t;const i=null===(o=(new Error).stack)||void 0===o?void 0:o.split("\n").map((e=>e.split("@"))),l=null==i?void 0:i.filter((([e,n])=>e.length>0&&"[native code]"!==n)),{file:u,line:c,keyValues:s}=null!=a?a:{};let _=null===(t=null==l?void 0:l[0])||void 0===t?void 0:t.filter((e=>e.length>0)).join("@");"Error"===_&&(_="webview::unknown"),await r("plugin:log|log",{level:e,message:n,location:_,file:u,line:c,keyValues:s})}return"function"==typeof SuppressedError&&SuppressedError,function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_CREATED="tauri://window-created",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_FILE_DROP="tauri://file-drop",e.WINDOW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WINDOW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled",e.MENU="tauri://menu"}(a||(a={})),function(e){e[e.Trace=1]="Trace",e[e.Debug=2]="Debug",e[e.Info=3]="Info",e[e.Warn=4]="Warn",e[e.Error=5]="Error"}(o||(o={})),e.attachConsole=async function(){return await t("log://log",(e=>{const n=e.payload,r=n.message.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,"");switch(n.level){case o.Trace:console.log(r);break;case o.Debug:console.debug(r);break;case o.Info:console.info(r);break;case o.Warn:console.warn(r);break;case o.Error:console.error(r);break;default:throw new Error(`unknown log level ${n.level}`)}}))},e.debug=async function(e,n){await i(o.Debug,e,n)},e.error=async function(e,n){await i(o.Error,e,n)},e.info=async function(e,n){await i(o.Info,e,n)},e.trace=async function(e,n){await i(o.Trace,e,n)},e.warn=async function(e,n){await i(o.Warn,e,n)},e}({});Object.defineProperty(window.__TAURI__,"log",{value:__TAURI_LOG__})}
|
||||||
|
|||||||
@@ -475,7 +475,7 @@ impl Builder {
|
|||||||
};
|
};
|
||||||
let app_handle = app_handle.clone();
|
let app_handle = app_handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
app_handle.emit_all("log://log", payload).unwrap();
|
app_handle.emit("log://log", payload).unwrap();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
|
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
|
||||||
|
|
||||||
## \[2.0.0-alpha.2]
|
## \[2.0.0-alpha.2]
|
||||||
|
|
||||||
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.16.
|
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
|
||||||
|
|
||||||
## \[2.0.0-alpha.3]
|
## \[2.0.0-alpha.3]
|
||||||
|
|
||||||
@@ -30,4 +34,4 @@
|
|||||||
## \[2.0.0-alpha.0]
|
## \[2.0.0-alpha.0]
|
||||||
|
|
||||||
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
ithub.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
ithub.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-notification"
|
name = "tauri-plugin-notification"
|
||||||
version = "2.0.0-alpha.4"
|
version = "2.0.0-alpha.5"
|
||||||
description = "Send desktop and mobile notifications on your Tauri application."
|
description = "Send desktop and mobile notifications on your Tauri application."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -9,7 +9,8 @@ rust-version = { workspace = true }
|
|||||||
links = "tauri-plugin-notification"
|
links = "tauri-plugin-notification"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = [ "dox" ]
|
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" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -34,4 +35,3 @@ win7-notifications = { version = "0.3.1", optional = true }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
windows7-compat = [ "win7-notifications" ]
|
windows7-compat = [ "win7-notifications" ]
|
||||||
dox = [ "tauri/dox" ]
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ dependencies {
|
|||||||
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("com.fasterxml.jackson.core:jackson-databind:2.15.3")
|
||||||
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")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<receiver android:name="app.tauri.notification.TimedNotificationPublisher" />
|
<receiver android:name="app.tauri.notification.TimedNotificationPublisher" />
|
||||||
<receiver android:name="app.tauri.notification.NotificationDismissReceiver" />
|
<receiver android:name="app.tauri.notification.NotificationDismissReceiver" />
|
||||||
<receiver
|
<receiver
|
||||||
android:name="app.tauri.notification.NotificationRestoreReceiver"
|
android:name="app.tauri.notification.LocalNotificationRestoreReceiver"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -12,21 +12,42 @@ import android.graphics.Color
|
|||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import app.tauri.Logger
|
import app.tauri.Logger
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.plugin.Invoke
|
import app.tauri.plugin.Invoke
|
||||||
import app.tauri.plugin.JSArray
|
import com.fasterxml.jackson.annotation.JsonValue
|
||||||
import app.tauri.plugin.JSObject
|
|
||||||
|
|
||||||
private const val CHANNEL_ID = "id"
|
enum class Importance(@JsonValue val value: Int) {
|
||||||
private const val CHANNEL_NAME = "name"
|
None(0),
|
||||||
private const val CHANNEL_DESCRIPTION = "description"
|
Min(1),
|
||||||
private const val CHANNEL_IMPORTANCE = "importance"
|
Low(2),
|
||||||
private const val CHANNEL_VISIBILITY = "visibility"
|
Default(3),
|
||||||
private const val CHANNEL_SOUND = "sound"
|
High(4);
|
||||||
private const val CHANNEL_VIBRATE = "vibration"
|
}
|
||||||
private const val CHANNEL_USE_LIGHTS = "lights"
|
|
||||||
private const val CHANNEL_LIGHT_COLOR = "lightColor"
|
enum class Visibility(@JsonValue val value: Int) {
|
||||||
|
Secret(-1),
|
||||||
|
Private(0),
|
||||||
|
Public(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class Channel {
|
||||||
|
lateinit var id: String
|
||||||
|
lateinit var name: String
|
||||||
|
var description: String? = null
|
||||||
|
var sound: String? = null
|
||||||
|
var lights: Boolean? = null
|
||||||
|
var lightsColor: String? = null
|
||||||
|
var vibration: Boolean? = null
|
||||||
|
var importance: Importance? = null
|
||||||
|
var visibility: Visibility? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class DeleteChannelArgs {
|
||||||
|
lateinit var id: String
|
||||||
|
}
|
||||||
|
|
||||||
class ChannelManager(private var context: Context) {
|
class ChannelManager(private var context: Context) {
|
||||||
private var notificationManager: NotificationManager? = null
|
private var notificationManager: NotificationManager? = null
|
||||||
@@ -38,32 +59,7 @@ class ChannelManager(private var context: Context) {
|
|||||||
|
|
||||||
fun createChannel(invoke: Invoke) {
|
fun createChannel(invoke: Invoke) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channel = JSObject()
|
val channel = invoke.parseArgs(Channel::class.java)
|
||||||
if (invoke.getString(CHANNEL_ID) != null) {
|
|
||||||
channel.put(CHANNEL_ID, invoke.getString(CHANNEL_ID))
|
|
||||||
} else {
|
|
||||||
invoke.reject("Channel missing identifier")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (invoke.getString(CHANNEL_NAME) != null) {
|
|
||||||
channel.put(CHANNEL_NAME, invoke.getString(CHANNEL_NAME))
|
|
||||||
} else {
|
|
||||||
invoke.reject("Channel missing name")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
channel.put(
|
|
||||||
CHANNEL_IMPORTANCE,
|
|
||||||
invoke.getInt(CHANNEL_IMPORTANCE, NotificationManager.IMPORTANCE_DEFAULT)
|
|
||||||
)
|
|
||||||
channel.put(CHANNEL_DESCRIPTION, invoke.getString(CHANNEL_DESCRIPTION, ""))
|
|
||||||
channel.put(
|
|
||||||
CHANNEL_VISIBILITY,
|
|
||||||
invoke.getInt(CHANNEL_VISIBILITY, NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
)
|
|
||||||
channel.put(CHANNEL_SOUND, invoke.getString(CHANNEL_SOUND))
|
|
||||||
channel.put(CHANNEL_VIBRATE, invoke.getBoolean(CHANNEL_VIBRATE, false))
|
|
||||||
channel.put(CHANNEL_USE_LIGHTS, invoke.getBoolean(CHANNEL_USE_LIGHTS, false))
|
|
||||||
channel.put(CHANNEL_LIGHT_COLOR, invoke.getString(CHANNEL_LIGHT_COLOR))
|
|
||||||
createChannel(channel)
|
createChannel(channel)
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
} else {
|
} else {
|
||||||
@@ -71,18 +67,18 @@ class ChannelManager(private var context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createChannel(channel: JSObject) {
|
private fun createChannel(channel: Channel) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val notificationChannel = NotificationChannel(
|
val notificationChannel = NotificationChannel(
|
||||||
channel.getString(CHANNEL_ID),
|
channel.id,
|
||||||
channel.getString(CHANNEL_NAME),
|
channel.name,
|
||||||
channel.getInteger(CHANNEL_IMPORTANCE)!!
|
(channel.importance ?: Importance.Default).value
|
||||||
)
|
)
|
||||||
notificationChannel.description = channel.getString(CHANNEL_DESCRIPTION)
|
notificationChannel.description = channel.description
|
||||||
notificationChannel.lockscreenVisibility = channel.getInteger(CHANNEL_VISIBILITY, android.app.Notification.VISIBILITY_PRIVATE)
|
notificationChannel.lockscreenVisibility = (channel.visibility ?: Visibility.Private).value
|
||||||
notificationChannel.enableVibration(channel.getBoolean(CHANNEL_VIBRATE, false))
|
notificationChannel.enableVibration(channel.vibration ?: false)
|
||||||
notificationChannel.enableLights(channel.getBoolean(CHANNEL_USE_LIGHTS, false))
|
notificationChannel.enableLights(channel.lights ?: false)
|
||||||
val lightColor = channel.getString(CHANNEL_LIGHT_COLOR)
|
val lightColor = channel.lightsColor ?: ""
|
||||||
if (lightColor.isNotEmpty()) {
|
if (lightColor.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
notificationChannel.lightColor = Color.parseColor(lightColor)
|
notificationChannel.lightColor = Color.parseColor(lightColor)
|
||||||
@@ -94,7 +90,7 @@ class ChannelManager(private var context: Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sound = channel.getString(CHANNEL_SOUND)
|
var sound = channel.sound ?: ""
|
||||||
if (sound.isNotEmpty()) {
|
if (sound.isNotEmpty()) {
|
||||||
if (sound.contains(".")) {
|
if (sound.contains(".")) {
|
||||||
sound = sound.substring(0, sound.lastIndexOf('.'))
|
sound = sound.substring(0, sound.lastIndexOf('.'))
|
||||||
@@ -113,8 +109,8 @@ class ChannelManager(private var context: Context) {
|
|||||||
|
|
||||||
fun deleteChannel(invoke: Invoke) {
|
fun deleteChannel(invoke: Invoke) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channelId = invoke.getString("id")
|
val args = invoke.parseArgs(DeleteChannelArgs::class.java)
|
||||||
notificationManager?.deleteNotificationChannel(channelId)
|
notificationManager?.deleteNotificationChannel(args.id)
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
} else {
|
} else {
|
||||||
invoke.reject("channel not available")
|
invoke.reject("channel not available")
|
||||||
@@ -125,28 +121,29 @@ class ChannelManager(private var context: Context) {
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val notificationChannels: List<NotificationChannel> =
|
val notificationChannels: List<NotificationChannel> =
|
||||||
notificationManager?.notificationChannels ?: listOf()
|
notificationManager?.notificationChannels ?: listOf()
|
||||||
val channels = JSArray()
|
|
||||||
|
val channels = mutableListOf<Channel>()
|
||||||
|
|
||||||
for (notificationChannel in notificationChannels) {
|
for (notificationChannel in notificationChannels) {
|
||||||
val channel = JSObject()
|
val channel = Channel()
|
||||||
channel.put(CHANNEL_ID, notificationChannel.id)
|
channel.id = notificationChannel.id
|
||||||
channel.put(CHANNEL_NAME, notificationChannel.name)
|
channel.name = notificationChannel.name.toString()
|
||||||
channel.put(CHANNEL_DESCRIPTION, notificationChannel.description)
|
channel.description = notificationChannel.description
|
||||||
channel.put(CHANNEL_IMPORTANCE, notificationChannel.importance)
|
channel.sound = notificationChannel.sound.toString()
|
||||||
channel.put(CHANNEL_VISIBILITY, notificationChannel.lockscreenVisibility)
|
channel.lights = notificationChannel.shouldShowLights()
|
||||||
channel.put(CHANNEL_SOUND, notificationChannel.sound)
|
String.format(
|
||||||
channel.put(CHANNEL_VIBRATE, notificationChannel.shouldVibrate())
|
|
||||||
channel.put(CHANNEL_USE_LIGHTS, notificationChannel.shouldShowLights())
|
|
||||||
channel.put(
|
|
||||||
CHANNEL_LIGHT_COLOR, String.format(
|
|
||||||
"#%06X",
|
"#%06X",
|
||||||
0xFFFFFF and notificationChannel.lightColor
|
0xFFFFFF and notificationChannel.lightColor
|
||||||
)
|
)
|
||||||
)
|
channel.vibration = notificationChannel.shouldVibrate()
|
||||||
channels.put(channel)
|
channel.importance = Importance.values().firstOrNull { it.value == notificationChannel.importance }
|
||||||
|
channel.visibility = Visibility.values().firstOrNull { it.value == notificationChannel.lockscreenVisibility }
|
||||||
|
|
||||||
|
channels.add(channel)
|
||||||
}
|
}
|
||||||
val result = JSObject()
|
|
||||||
result.put("channels", channels)
|
invoke.resolveObject(channels)
|
||||||
invoke.resolve(result)
|
|
||||||
} else {
|
} else {
|
||||||
invoke.reject("channel not available")
|
invoke.reject("channel not available")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,22 @@ import android.content.ContentResolver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.plugin.JSArray
|
import app.tauri.plugin.JSArray
|
||||||
import app.tauri.plugin.JSObject
|
import app.tauri.plugin.JSObject
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
class Notification {
|
class Notification {
|
||||||
|
var id: Int = 0
|
||||||
var title: String? = null
|
var title: String? = null
|
||||||
var body: String? = null
|
var body: String? = null
|
||||||
var largeBody: String? = null
|
var largeBody: String? = null
|
||||||
var summary: String? = null
|
var summary: String? = null
|
||||||
var id: Int = 0
|
var sound: String? = null
|
||||||
private var sound: String? = null
|
var icon: String? = null
|
||||||
private var smallIcon: String? = null
|
var largeIcon: String? = null
|
||||||
private var largeIcon: String? = null
|
|
||||||
var iconColor: String? = null
|
var iconColor: String? = null
|
||||||
var actionTypeId: String? = null
|
var actionTypeId: String? = null
|
||||||
var group: String? = null
|
var group: String? = null
|
||||||
@@ -33,7 +35,7 @@ class Notification {
|
|||||||
var attachments: List<NotificationAttachment>? = null
|
var attachments: List<NotificationAttachment>? = null
|
||||||
var schedule: NotificationSchedule? = null
|
var schedule: NotificationSchedule? = null
|
||||||
var channelId: String? = null
|
var channelId: String? = null
|
||||||
var source: JSObject? = null
|
var sourceJson: String? = null
|
||||||
var visibility: Int? = null
|
var visibility: Int? = null
|
||||||
var number: Int? = null
|
var number: Int? = null
|
||||||
|
|
||||||
@@ -54,18 +56,6 @@ class Notification {
|
|||||||
return soundPath
|
return soundPath
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSound(sound: String?) {
|
|
||||||
this.sound = sound
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSmallIcon(smallIcon: String?) {
|
|
||||||
this.smallIcon = AssetUtils.getResourceBaseName(smallIcon)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setLargeIcon(largeIcon: String?) {
|
|
||||||
this.largeIcon = AssetUtils.getResourceBaseName(largeIcon)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getIconColor(globalColor: String): String {
|
fun getIconColor(globalColor: String): String {
|
||||||
// use the one defined local before trying for a globally defined color
|
// use the one defined local before trying for a globally defined color
|
||||||
return iconColor ?: globalColor
|
return iconColor ?: globalColor
|
||||||
@@ -73,8 +63,8 @@ class Notification {
|
|||||||
|
|
||||||
fun getSmallIcon(context: Context, defaultIcon: Int): Int {
|
fun getSmallIcon(context: Context, defaultIcon: Int): Int {
|
||||||
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
||||||
if (smallIcon != null) {
|
if (icon != null) {
|
||||||
resId = AssetUtils.getResourceID(context, smallIcon, "drawable")
|
resId = AssetUtils.getResourceID(context, icon, "drawable")
|
||||||
}
|
}
|
||||||
if (resId == AssetUtils.RESOURCE_ID_ZERO_VALUE) {
|
if (resId == AssetUtils.RESOURCE_ID_ZERO_VALUE) {
|
||||||
resId = defaultIcon
|
resId = defaultIcon
|
||||||
@@ -93,77 +83,15 @@ class Notification {
|
|||||||
val isScheduled = schedule != null
|
val isScheduled = schedule != null
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJson(jsonNotification: JSONObject): Notification {
|
fun buildNotificationPendingList(notifications: List<Notification>): List<PendingNotification> {
|
||||||
val notification: JSObject = try {
|
val pendingNotifications = mutableListOf<PendingNotification>()
|
||||||
val identifier = jsonNotification.getLong("id")
|
|
||||||
if (identifier > Int.MAX_VALUE || identifier < Int.MIN_VALUE) {
|
|
||||||
throw Exception("The notification identifier should be a 32-bit integer")
|
|
||||||
}
|
|
||||||
JSObject.fromJSONObject(jsonNotification)
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
throw Exception("Invalid notification JSON object", e)
|
|
||||||
}
|
|
||||||
return fromJSObject(notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromJSObject(jsonObject: JSObject): Notification {
|
|
||||||
val notification = Notification()
|
|
||||||
notification.source = jsonObject
|
|
||||||
notification.id = jsonObject.getInteger("id") ?: throw Exception("Missing notification identifier")
|
|
||||||
notification.body = jsonObject.getString("body", null)
|
|
||||||
notification.largeBody = jsonObject.getString("largeBody", null)
|
|
||||||
notification.summary = jsonObject.getString("summary", null)
|
|
||||||
notification.actionTypeId = jsonObject.getString("actionTypeId", null)
|
|
||||||
notification.group = jsonObject.getString("group", null)
|
|
||||||
notification.setSound(jsonObject.getString("sound", null))
|
|
||||||
notification.title = jsonObject.getString("title", null)
|
|
||||||
notification.setSmallIcon(jsonObject.getString("icon", null))
|
|
||||||
notification.setLargeIcon(jsonObject.getString("largeIcon", null))
|
|
||||||
notification.iconColor = jsonObject.getString("iconColor", null)
|
|
||||||
notification.attachments = NotificationAttachment.getAttachments(jsonObject)
|
|
||||||
notification.isGroupSummary = jsonObject.getBoolean("groupSummary", false)
|
|
||||||
notification.channelId = jsonObject.getString("channelId", null)
|
|
||||||
val schedule = jsonObject.getJSObject("schedule")
|
|
||||||
if (schedule != null) {
|
|
||||||
notification.schedule = NotificationSchedule(schedule)
|
|
||||||
}
|
|
||||||
notification.extra = jsonObject.getJSObject("extra")
|
|
||||||
notification.isOngoing = jsonObject.getBoolean("ongoing", false)
|
|
||||||
notification.isAutoCancel = jsonObject.getBoolean("autoCancel", true)
|
|
||||||
notification.visibility = jsonObject.getInteger("visibility")
|
|
||||||
notification.number = jsonObject.getInteger("number")
|
|
||||||
try {
|
|
||||||
val inboxLines = jsonObject.getJSONArray("inboxLines")
|
|
||||||
val inboxStringList: MutableList<String> = ArrayList()
|
|
||||||
for (i in 0 until inboxLines.length()) {
|
|
||||||
inboxStringList.add(inboxLines.getString(i))
|
|
||||||
}
|
|
||||||
notification.inboxLines = inboxStringList
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
return notification
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildNotificationPendingList(notifications: List<Notification>): JSObject {
|
|
||||||
val result = JSObject()
|
|
||||||
val jsArray = JSArray()
|
|
||||||
for (notification in notifications) {
|
for (notification in notifications) {
|
||||||
val jsNotification = JSObject()
|
val pendingNotification = PendingNotification(notification.id, notification.title, notification.body, notification.schedule, notification.extra)
|
||||||
jsNotification.put("id", notification.id)
|
pendingNotifications.add(pendingNotification)
|
||||||
jsNotification.put("title", notification.title)
|
|
||||||
jsNotification.put("body", notification.body)
|
|
||||||
val schedule = notification.schedule
|
|
||||||
if (schedule != null) {
|
|
||||||
val jsSchedule = JSObject()
|
|
||||||
jsSchedule.put("kind", schedule.scheduleObj.getString("kind", null))
|
|
||||||
jsSchedule.put("data", schedule.scheduleObj.getJSObject("data"))
|
|
||||||
jsNotification.put("schedule", jsSchedule)
|
|
||||||
}
|
}
|
||||||
jsNotification.put("extra", notification.extra)
|
return pendingNotifications
|
||||||
jsArray.put(jsNotification)
|
|
||||||
}
|
|
||||||
result.put("notifications", jsArray)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PendingNotification(val id: Int, val title: String?, val body: String?, val schedule: NotificationSchedule?, val extra: JSObject?)
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package app.tauri.notification
|
|
||||||
|
|
||||||
import app.tauri.Logger
|
|
||||||
import app.tauri.plugin.JSArray
|
|
||||||
import app.tauri.plugin.JSObject
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
class NotificationAction() {
|
|
||||||
var id: String? = null
|
|
||||||
var title: String? = null
|
|
||||||
var input = false
|
|
||||||
|
|
||||||
constructor(id: String?, title: String?, input: Boolean): this() {
|
|
||||||
this.id = id
|
|
||||||
this.title = title
|
|
||||||
this.input = input
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun buildTypes(types: JSArray): Map<String, List<NotificationAction>> {
|
|
||||||
val actionTypeMap: MutableMap<String, List<NotificationAction>> = HashMap()
|
|
||||||
try {
|
|
||||||
val objects: List<JSONObject> = types.toList()
|
|
||||||
for (obj in objects) {
|
|
||||||
val jsObject = JSObject.fromJSONObject(
|
|
||||||
obj
|
|
||||||
)
|
|
||||||
val actionGroupId = jsObject.getString("id")
|
|
||||||
val actions = jsObject.getJSONArray("actions")
|
|
||||||
val typesArray = mutableListOf<NotificationAction>()
|
|
||||||
for (i in 0 until actions.length()) {
|
|
||||||
val notificationAction = NotificationAction()
|
|
||||||
val action = JSObject.fromJSONObject(actions.getJSONObject(i))
|
|
||||||
notificationAction.id = action.getString("id")
|
|
||||||
notificationAction.title = action.getString("title")
|
|
||||||
notificationAction.input = action.getBoolean("input")
|
|
||||||
typesArray.add(notificationAction)
|
|
||||||
}
|
|
||||||
actionTypeMap[actionGroupId] = typesArray.toList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Logger.error(Logger.tags("Notification"), "Error when building action types", e)
|
|
||||||
}
|
|
||||||
return actionTypeMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ import android.os.Build
|
|||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import app.tauri.PermissionState
|
import app.tauri.PermissionState
|
||||||
import app.tauri.annotation.Command
|
import app.tauri.annotation.Command
|
||||||
|
import app.tauri.annotation.InvokeArg
|
||||||
import app.tauri.annotation.Permission
|
import app.tauri.annotation.Permission
|
||||||
import app.tauri.annotation.PermissionCallback
|
import app.tauri.annotation.PermissionCallback
|
||||||
import app.tauri.annotation.TauriPlugin
|
import app.tauri.annotation.TauriPlugin
|
||||||
@@ -21,11 +22,55 @@ import app.tauri.plugin.Invoke
|
|||||||
import app.tauri.plugin.JSArray
|
import app.tauri.plugin.JSArray
|
||||||
import app.tauri.plugin.JSObject
|
import app.tauri.plugin.JSObject
|
||||||
import app.tauri.plugin.Plugin
|
import app.tauri.plugin.Plugin
|
||||||
import org.json.JSONException
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
const val LOCAL_NOTIFICATIONS = "permissionState"
|
const val LOCAL_NOTIFICATIONS = "permissionState"
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class PluginConfig {
|
||||||
|
var icon: String? = null
|
||||||
|
var sound: String? = null
|
||||||
|
var iconColor: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class BatchArgs {
|
||||||
|
lateinit var notifications: List<Notification>
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class CancelArgs {
|
||||||
|
lateinit var notifications: List<Int>
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class NotificationAction {
|
||||||
|
lateinit var id: String
|
||||||
|
var title: String? = null
|
||||||
|
var input: Boolean? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class ActionType {
|
||||||
|
lateinit var id: String
|
||||||
|
lateinit var actions: List<NotificationAction>
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class RegisterActionTypesArgs {
|
||||||
|
lateinit var types: List<ActionType>
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class ActiveNotification {
|
||||||
|
var id: Int = 0
|
||||||
|
var tag: String? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvokeArg
|
||||||
|
class RemoveActiveArgs {
|
||||||
|
var notifications: List<ActiveNotification> = listOf()
|
||||||
|
}
|
||||||
|
|
||||||
@TauriPlugin(
|
@TauriPlugin(
|
||||||
permissions = [
|
permissions = [
|
||||||
Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "permissionState")
|
Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "permissionState")
|
||||||
@@ -41,8 +86,8 @@ class NotificationPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
companion object {
|
companion object {
|
||||||
var instance: NotificationPlugin? = null
|
var instance: NotificationPlugin? = null
|
||||||
|
|
||||||
fun triggerNotification(notification: JSObject) {
|
fun triggerNotification(notification: Notification) {
|
||||||
instance?.trigger("notification", notification)
|
instance?.triggerObject("notification", notification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,23 +96,32 @@ class NotificationPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
|
|
||||||
super.load(webView)
|
super.load(webView)
|
||||||
this.webView = webView
|
this.webView = webView
|
||||||
notificationStorage = NotificationStorage(activity)
|
notificationStorage = NotificationStorage(activity, jsonMapper())
|
||||||
|
|
||||||
val manager = TauriNotificationManager(
|
val manager = TauriNotificationManager(
|
||||||
notificationStorage,
|
notificationStorage,
|
||||||
activity,
|
activity,
|
||||||
activity,
|
activity,
|
||||||
getConfig()
|
getConfig(PluginConfig::class.java)
|
||||||
)
|
)
|
||||||
manager.createNotificationChannel()
|
manager.createNotificationChannel()
|
||||||
|
|
||||||
this.manager = manager
|
this.manager = manager
|
||||||
|
|
||||||
notificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
notificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
val intent = activity.intent
|
||||||
|
intent?.let {
|
||||||
|
onIntent(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
|
onIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onIntent(intent: Intent) {
|
||||||
if (Intent.ACTION_MAIN != intent.action) {
|
if (Intent.ACTION_MAIN != intent.action) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -79,80 +133,43 @@ class NotificationPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun show(invoke: Invoke) {
|
fun show(invoke: Invoke) {
|
||||||
val notification = Notification.fromJSObject(invoke.data)
|
val notification = invoke.parseArgs(Notification::class.java)
|
||||||
val id = manager.schedule(notification)
|
val id = manager.schedule(notification)
|
||||||
|
|
||||||
val returnVal = JSObject().put("id", id)
|
invoke.resolveObject(id)
|
||||||
invoke.resolve(returnVal)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun batch(invoke: Invoke) {
|
fun batch(invoke: Invoke) {
|
||||||
val notificationArray = invoke.getArray("notifications")
|
val args = invoke.parseArgs(BatchArgs::class.java)
|
||||||
if (notificationArray == null) {
|
|
||||||
invoke.reject("Missing `notifications` argument")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val notifications: MutableList<Notification> =
|
val ids = manager.schedule(args.notifications)
|
||||||
ArrayList(notificationArray.length())
|
notificationStorage.appendNotifications(args.notifications)
|
||||||
val notificationsInput: List<JSONObject> = try {
|
|
||||||
notificationArray.toList()
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
invoke.reject("Provided notification format is invalid")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (jsonNotification in notificationsInput) {
|
invoke.resolveObject(ids)
|
||||||
val notification = Notification.fromJson(jsonNotification)
|
|
||||||
notifications.add(notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
val ids = manager.schedule(notifications)
|
|
||||||
notificationStorage.appendNotifications(notifications)
|
|
||||||
|
|
||||||
val result = JSObject()
|
|
||||||
result.put("notifications", ids)
|
|
||||||
invoke.resolve(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun cancel(invoke: Invoke) {
|
fun cancel(invoke: Invoke) {
|
||||||
val notifications: List<Int> = invoke.getArray("notifications", JSArray()).toList()
|
val args = invoke.parseArgs(CancelArgs::class.java)
|
||||||
if (notifications.isEmpty()) {
|
manager.cancel(args.notifications)
|
||||||
invoke.reject("Must provide notifications array as notifications option")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.cancel(notifications)
|
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun removeActive(invoke: Invoke) {
|
fun removeActive(invoke: Invoke) {
|
||||||
val notifications = invoke.getArray("notifications")
|
val args = invoke.parseArgs(RemoveActiveArgs::class.java)
|
||||||
if (notifications == null) {
|
|
||||||
|
if (args.notifications.isEmpty()) {
|
||||||
notificationManager.cancelAll()
|
notificationManager.cancelAll()
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
} else {
|
} else {
|
||||||
try {
|
for (notification in args.notifications) {
|
||||||
for (o in notifications.toList<Any>()) {
|
if (notification.tag == null) {
|
||||||
if (o is JSONObject) {
|
notificationManager.cancel(notification.id)
|
||||||
val notification = JSObject.fromJSONObject((o))
|
|
||||||
val tag = notification.getString("tag", null)
|
|
||||||
val id = notification.getInteger("id", 0)
|
|
||||||
if (tag == null) {
|
|
||||||
notificationManager.cancel(id)
|
|
||||||
} else {
|
} else {
|
||||||
notificationManager.cancel(tag, id)
|
notificationManager.cancel(notification.tag, notification.id)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
invoke.reject("Unexpected notification type")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
invoke.reject(e.message)
|
|
||||||
}
|
}
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
}
|
}
|
||||||
@@ -162,14 +179,13 @@ class NotificationPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
fun getPending(invoke: Invoke) {
|
fun getPending(invoke: Invoke) {
|
||||||
val notifications= notificationStorage.getSavedNotifications()
|
val notifications= notificationStorage.getSavedNotifications()
|
||||||
val result = Notification.buildNotificationPendingList(notifications)
|
val result = Notification.buildNotificationPendingList(notifications)
|
||||||
invoke.resolve(result)
|
invoke.resolveObject(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
fun registerActionTypes(invoke: Invoke) {
|
fun registerActionTypes(invoke: Invoke) {
|
||||||
val types = invoke.getArray("types", JSArray())
|
val args = invoke.parseArgs(RegisterActionTypesArgs::class.java)
|
||||||
val typesArray = NotificationAction.buildTypes(types)
|
notificationStorage.writeActionGroup(args.types)
|
||||||
notificationStorage.writeActionGroup(typesArray)
|
|
||||||
invoke.resolve()
|
invoke.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,9 +217,8 @@ class NotificationPlugin(private val activity: Activity): Plugin(activity) {
|
|||||||
notifications.put(jsNotification)
|
notifications.put(jsNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val result = JSObject()
|
|
||||||
result.put("notifications", notifications)
|
invoke.resolveObject(notifications)
|
||||||
invoke.resolve(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command
|
@Command
|
||||||
|
|||||||
@@ -5,13 +5,26 @@
|
|||||||
package app.tauri.notification
|
package app.tauri.notification
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ClipData.Item
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import app.tauri.plugin.JSObject
|
import com.fasterxml.jackson.annotation.JsonFormat
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator
|
||||||
|
import com.fasterxml.jackson.core.JsonParser
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||||
|
import java.io.IOException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
|
||||||
const val JS_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
const val JS_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
||||||
|
|
||||||
enum class NotificationInterval {
|
enum class NotificationInterval {
|
||||||
@@ -33,71 +46,89 @@ fun getIntervalTime(interval: NotificationInterval, count: Int): Long {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class ScheduleKind {
|
@JsonDeserialize(using = NotificationScheduleDeserializer::class)
|
||||||
|
@JsonSerialize(using = NotificationScheduleSerializer::class)
|
||||||
|
sealed class NotificationSchedule {
|
||||||
// At specific moment of time (with repeating option)
|
// At specific moment of time (with repeating option)
|
||||||
class At(var date: Date, val repeating: Boolean): ScheduleKind()
|
class At(@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = JS_DATE_FORMAT) var date: Date, val repeating: Boolean = false, val allowWhileIdle: Boolean = false): NotificationSchedule()
|
||||||
class Interval(val interval: DateMatch): ScheduleKind()
|
class Interval(val interval: DateMatch, val allowWhileIdle: Boolean = false): NotificationSchedule()
|
||||||
class Every(val interval: NotificationInterval, val count: Int): ScheduleKind()
|
class Every(val interval: NotificationInterval, val count: Int = 0, val allowWhileIdle: Boolean = false): NotificationSchedule()
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SimpleDateFormat")
|
|
||||||
class NotificationSchedule(val scheduleObj: JSObject) {
|
|
||||||
val kind: ScheduleKind
|
|
||||||
// Schedule this notification to fire even if app is idled (Doze)
|
|
||||||
var whileIdle: Boolean = false
|
|
||||||
|
|
||||||
init {
|
|
||||||
val payload = scheduleObj.getJSObject("data", JSObject())
|
|
||||||
|
|
||||||
when (val scheduleKind = scheduleObj.getString("kind", "")) {
|
|
||||||
"At" -> {
|
|
||||||
val dateString = payload.getString("date")
|
|
||||||
if (dateString.isNotEmpty()) {
|
|
||||||
val sdf = SimpleDateFormat(JS_DATE_FORMAT)
|
|
||||||
sdf.timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
val at = sdf.parse(dateString)
|
|
||||||
if (at == null) {
|
|
||||||
throw Exception("could not parse `at` date")
|
|
||||||
} else {
|
|
||||||
kind = ScheduleKind.At(at, payload.getBoolean("repeating"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw Exception("`at` date cannot be empty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Interval" -> {
|
|
||||||
val dateMatch = onFromJson(payload)
|
|
||||||
kind = ScheduleKind.Interval(dateMatch)
|
|
||||||
}
|
|
||||||
"Every" -> {
|
|
||||||
val interval = NotificationInterval.valueOf(payload.getString("interval"))
|
|
||||||
kind = ScheduleKind.Every(interval, payload.getInteger("count", 1))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
throw Exception("Unknown schedule kind $scheduleKind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
whileIdle = scheduleObj.getBoolean("allowWhileIdle", false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onFromJson(onJson: JSObject): DateMatch {
|
|
||||||
val match = DateMatch()
|
|
||||||
match.year = onJson.getInteger("year")
|
|
||||||
match.month = onJson.getInteger("month")
|
|
||||||
match.day = onJson.getInteger("day")
|
|
||||||
match.weekday = onJson.getInteger("weekday")
|
|
||||||
match.hour = onJson.getInteger("hour")
|
|
||||||
match.minute = onJson.getInteger("minute")
|
|
||||||
match.second = onJson.getInteger("second")
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isRemovable(): Boolean {
|
fun isRemovable(): Boolean {
|
||||||
return when (kind) {
|
return when (this) {
|
||||||
is ScheduleKind.At -> !kind.repeating
|
is At -> !repeating
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun allowWhileIdle(): Boolean {
|
||||||
|
return when (this) {
|
||||||
|
is At -> allowWhileIdle
|
||||||
|
is Interval -> allowWhileIdle
|
||||||
|
is Every -> allowWhileIdle
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class NotificationScheduleSerializer @JvmOverloads constructor(t: Class<NotificationSchedule>? = null) :
|
||||||
|
StdSerializer<NotificationSchedule>(t) {
|
||||||
|
@SuppressLint("SimpleDateFormat")
|
||||||
|
@Throws(IOException::class, JsonProcessingException::class)
|
||||||
|
override fun serialize(
|
||||||
|
value: NotificationSchedule, jgen: JsonGenerator, provider: SerializerProvider
|
||||||
|
) {
|
||||||
|
jgen.writeStartObject()
|
||||||
|
when (value) {
|
||||||
|
is NotificationSchedule.At -> {
|
||||||
|
jgen.writeObjectFieldStart("at")
|
||||||
|
|
||||||
|
val sdf = SimpleDateFormat(JS_DATE_FORMAT)
|
||||||
|
sdf.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
jgen.writeStringField("date", sdf.format(value.date))
|
||||||
|
jgen.writeBooleanField("repeating", value.repeating)
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
is NotificationSchedule.Interval -> {
|
||||||
|
jgen.writeObjectFieldStart("interval")
|
||||||
|
|
||||||
|
jgen.writeObjectField("interval", value.interval)
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
is NotificationSchedule.Every -> {
|
||||||
|
jgen.writeObjectFieldStart("every")
|
||||||
|
|
||||||
|
jgen.writeObjectField("interval", value.interval)
|
||||||
|
jgen.writeNumberField("count", value.count)
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
jgen.writeEndObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class NotificationScheduleDeserializer: JsonDeserializer<NotificationSchedule>() {
|
||||||
|
override fun deserialize(
|
||||||
|
jsonParser: JsonParser,
|
||||||
|
deserializationContext: DeserializationContext
|
||||||
|
): NotificationSchedule {
|
||||||
|
val node: JsonNode = jsonParser.codec.readTree(jsonParser)
|
||||||
|
node.get("at")?.let {
|
||||||
|
return jsonParser.codec.treeToValue(it, NotificationSchedule.At::class.java)
|
||||||
|
}
|
||||||
|
node.get("interval")?.let {
|
||||||
|
return jsonParser.codec.treeToValue(it, NotificationSchedule.Interval::class.java)
|
||||||
|
}
|
||||||
|
node.get("every")?.let {
|
||||||
|
return jsonParser.codec.treeToValue(it, NotificationSchedule.Every::class.java)
|
||||||
|
}
|
||||||
|
throw Error("unknown schedule kind $node")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DateMatch {
|
class DateMatch {
|
||||||
|
|||||||
@@ -6,23 +6,23 @@ package app.tauri.notification
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import app.tauri.plugin.JSObject
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import java.text.ParseException
|
import java.lang.Exception
|
||||||
|
|
||||||
// Key for private preferences
|
// Key for private preferences
|
||||||
private const val NOTIFICATION_STORE_ID = "NOTIFICATION_STORE"
|
private const val NOTIFICATION_STORE_ID = "NOTIFICATION_STORE"
|
||||||
// Key used to save action types
|
// Key used to save action types
|
||||||
private const val ACTION_TYPES_ID = "ACTION_TYPE_STORE"
|
private const val ACTION_TYPES_ID = "ACTION_TYPE_STORE"
|
||||||
|
|
||||||
class NotificationStorage(private val context: Context) {
|
class NotificationStorage(private val context: Context, private val jsonMapper: ObjectMapper) {
|
||||||
fun appendNotifications(localNotifications: List<Notification>) {
|
fun appendNotifications(localNotifications: List<Notification>) {
|
||||||
val storage = getStorage(NOTIFICATION_STORE_ID)
|
val storage = getStorage(NOTIFICATION_STORE_ID)
|
||||||
val editor = storage.edit()
|
val editor = storage.edit()
|
||||||
for (request in localNotifications) {
|
for (request in localNotifications) {
|
||||||
if (request.isScheduled) {
|
if (request.isScheduled) {
|
||||||
val key: String = request.id.toString()
|
val key: String = request.id.toString()
|
||||||
editor.putString(key, request.source.toString())
|
editor.putString(key, request.sourceJson.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
editor.apply()
|
editor.apply()
|
||||||
@@ -43,34 +43,17 @@ class NotificationStorage(private val context: Context) {
|
|||||||
val notifications = ArrayList<Notification>()
|
val notifications = ArrayList<Notification>()
|
||||||
for (key in all.keys) {
|
for (key in all.keys) {
|
||||||
val notificationString = all[key] as String?
|
val notificationString = all[key] as String?
|
||||||
val jsNotification = getNotificationFromJSONString(notificationString)
|
|
||||||
if (jsNotification != null) {
|
|
||||||
try {
|
try {
|
||||||
val notification =
|
val notification = jsonMapper.readValue(notificationString, Notification::class.java)
|
||||||
Notification.fromJSObject(jsNotification)
|
|
||||||
notifications.add(notification)
|
notifications.add(notification)
|
||||||
} catch (_: ParseException) {
|
} catch (_: Exception) { }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return notifications
|
return notifications
|
||||||
}
|
}
|
||||||
return ArrayList()
|
return ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNotificationFromJSONString(notificationString: String?): JSObject? {
|
fun getSavedNotification(key: String): Notification? {
|
||||||
if (notificationString == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val jsNotification = try {
|
|
||||||
JSObject(notificationString)
|
|
||||||
} catch (ex: JSONException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return jsNotification
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSavedNotificationAsJSObject(key: String?): JSObject? {
|
|
||||||
val storage = getStorage(NOTIFICATION_STORE_ID)
|
val storage = getStorage(NOTIFICATION_STORE_ID)
|
||||||
val notificationString = try {
|
val notificationString = try {
|
||||||
storage.getString(key, null)
|
storage.getString(key, null)
|
||||||
@@ -78,22 +61,11 @@ class NotificationStorage(private val context: Context) {
|
|||||||
return null
|
return null
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
val jsNotification = try {
|
return try {
|
||||||
JSObject(notificationString)
|
jsonMapper.readValue(notificationString, Notification::class.java)
|
||||||
} catch (ex: JSONException) {
|
} catch (ex: JSONException) {
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
return jsNotification
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSavedNotification(key: String?): Notification? {
|
|
||||||
val jsNotification = getSavedNotificationAsJSObject(key) ?: return null
|
|
||||||
val notification = try {
|
|
||||||
Notification.fromJSObject(jsNotification)
|
|
||||||
} catch (ex: ParseException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return notification
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteNotification(id: String?) {
|
fun deleteNotification(id: String?) {
|
||||||
@@ -106,15 +78,16 @@ class NotificationStorage(private val context: Context) {
|
|||||||
return context.getSharedPreferences(key, Context.MODE_PRIVATE)
|
return context.getSharedPreferences(key, Context.MODE_PRIVATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeActionGroup(typesMap: Map<String, List<NotificationAction>>) {
|
fun writeActionGroup(actions: List<ActionType>) {
|
||||||
for ((id, notificationActions) in typesMap) {
|
for (type in actions) {
|
||||||
val editor = getStorage(ACTION_TYPES_ID + id).edit()
|
val i = type.id
|
||||||
|
val editor = getStorage(ACTION_TYPES_ID + type.id).edit()
|
||||||
editor.clear()
|
editor.clear()
|
||||||
editor.putInt("count", notificationActions.size)
|
editor.putInt("count", type.actions.size)
|
||||||
for (i in notificationActions.indices) {
|
for (action in type.actions) {
|
||||||
editor.putString("id$i", notificationActions[i].id)
|
editor.putString("id$i", action.id)
|
||||||
editor.putString("title$i", notificationActions[i].title)
|
editor.putString("title$i", action.title)
|
||||||
editor.putBoolean("input$i", notificationActions[i].input)
|
editor.putBoolean("input$i", action.input ?: false)
|
||||||
}
|
}
|
||||||
editor.apply()
|
editor.apply()
|
||||||
}
|
}
|
||||||
@@ -128,7 +101,12 @@ class NotificationStorage(private val context: Context) {
|
|||||||
val id = storage.getString("id$i", "")
|
val id = storage.getString("id$i", "")
|
||||||
val title = storage.getString("title$i", "")
|
val title = storage.getString("title$i", "")
|
||||||
val input = storage.getBoolean("input$i", false)
|
val input = storage.getBoolean("input$i", false)
|
||||||
actions[i] = NotificationAction(id, title, input)
|
|
||||||
|
val action = NotificationAction()
|
||||||
|
action.id = id ?: ""
|
||||||
|
action.title = title
|
||||||
|
action.input = input
|
||||||
|
actions[i] = action
|
||||||
}
|
}
|
||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.core.app.RemoteInput
|
|||||||
import app.tauri.Logger
|
import app.tauri.Logger
|
||||||
import app.tauri.plugin.JSObject
|
import app.tauri.plugin.JSObject
|
||||||
import app.tauri.plugin.PluginManager
|
import app.tauri.plugin.PluginManager
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@@ -44,7 +45,7 @@ class TauriNotificationManager(
|
|||||||
private val storage: NotificationStorage,
|
private val storage: NotificationStorage,
|
||||||
private val activity: Activity?,
|
private val activity: Activity?,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val config: JSObject
|
private val config: PluginConfig?
|
||||||
) {
|
) {
|
||||||
private var defaultSoundID: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
private var defaultSoundID: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
||||||
private var defaultSmallIconID: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
private var defaultSmallIconID: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
||||||
@@ -200,7 +201,7 @@ class TauriNotificationManager(
|
|||||||
mBuilder.setOnlyAlertOnce(true)
|
mBuilder.setOnlyAlertOnce(true)
|
||||||
mBuilder.setSmallIcon(notification.getSmallIcon(context, getDefaultSmallIcon(context)))
|
mBuilder.setSmallIcon(notification.getSmallIcon(context, getDefaultSmallIcon(context)))
|
||||||
mBuilder.setLargeIcon(notification.getLargeIcon(context))
|
mBuilder.setLargeIcon(notification.getLargeIcon(context))
|
||||||
val iconColor = notification.getIconColor(config.getString("iconColor"))
|
val iconColor = notification.getIconColor(config?.iconColor ?: "")
|
||||||
if (iconColor.isNotEmpty()) {
|
if (iconColor.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
mBuilder.color = Color.parseColor(iconColor)
|
mBuilder.color = Color.parseColor(iconColor)
|
||||||
@@ -216,7 +217,7 @@ class TauriNotificationManager(
|
|||||||
} else {
|
} else {
|
||||||
notificationManager.notify(notification.id, buildNotification)
|
notificationManager.notify(notification.id, buildNotification)
|
||||||
try {
|
try {
|
||||||
NotificationPlugin.triggerNotification(notification.source ?: JSObject())
|
NotificationPlugin.triggerNotification(notification)
|
||||||
} catch (_: JSONException) {
|
} catch (_: JSONException) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +255,7 @@ class TauriNotificationManager(
|
|||||||
notificationAction.title,
|
notificationAction.title,
|
||||||
actionPendingIntent
|
actionPendingIntent
|
||||||
)
|
)
|
||||||
if (notificationAction.input) {
|
if (notificationAction.input == true) {
|
||||||
val remoteInput = RemoteInput.Builder(REMOTE_INPUT_KEY).setLabel(
|
val remoteInput = RemoteInput.Builder(REMOTE_INPUT_KEY).setLabel(
|
||||||
notificationAction.title
|
notificationAction.title
|
||||||
).build()
|
).build()
|
||||||
@@ -298,7 +299,7 @@ class TauriNotificationManager(
|
|||||||
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
intent.putExtra(NOTIFICATION_INTENT_KEY, notification.id)
|
intent.putExtra(NOTIFICATION_INTENT_KEY, notification.id)
|
||||||
intent.putExtra(ACTION_INTENT_KEY, action)
|
intent.putExtra(ACTION_INTENT_KEY, action)
|
||||||
intent.putExtra(NOTIFICATION_OBJ_INTENT_KEY, notification.source.toString())
|
intent.putExtra(NOTIFICATION_OBJ_INTENT_KEY, notification.sourceJson)
|
||||||
val schedule = notification.schedule
|
val schedule = notification.schedule
|
||||||
intent.putExtra(NOTIFICATION_IS_REMOVABLE_KEY, schedule == null || schedule.isRemovable())
|
intent.putExtra(NOTIFICATION_IS_REMOVABLE_KEY, schedule == null || schedule.isRemovable())
|
||||||
return intent
|
return intent
|
||||||
@@ -326,23 +327,22 @@ class TauriNotificationManager(
|
|||||||
var pendingIntent =
|
var pendingIntent =
|
||||||
PendingIntent.getBroadcast(context, request.id, notificationIntent, flags)
|
PendingIntent.getBroadcast(context, request.id, notificationIntent, flags)
|
||||||
|
|
||||||
when (val scheduleKind = schedule?.kind) {
|
when (schedule) {
|
||||||
is ScheduleKind.At -> {
|
is NotificationSchedule.At -> {
|
||||||
val at = scheduleKind.date
|
if (schedule.date.time < Date().time) {
|
||||||
if (at.time < Date().time) {
|
|
||||||
Logger.error(Logger.tags("Notification"), "Scheduled time must be *after* current time", null)
|
Logger.error(Logger.tags("Notification"), "Scheduled time must be *after* current time", null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (scheduleKind.repeating) {
|
if (schedule.repeating) {
|
||||||
val interval: Long = at.time - Date().time
|
val interval: Long = schedule.date.time - Date().time
|
||||||
alarmManager.setRepeating(AlarmManager.RTC, at.time, interval, pendingIntent)
|
alarmManager.setRepeating(AlarmManager.RTC, schedule.date.time, interval, pendingIntent)
|
||||||
} else {
|
} else {
|
||||||
setExactIfPossible(alarmManager, schedule, at.time, pendingIntent)
|
setExactIfPossible(alarmManager, schedule, schedule.date.time, pendingIntent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ScheduleKind.Interval -> {
|
is NotificationSchedule.Interval -> {
|
||||||
val trigger = scheduleKind.interval.nextTrigger(Date())
|
val trigger = schedule.interval.nextTrigger(Date())
|
||||||
notificationIntent.putExtra(TimedNotificationPublisher.CRON_KEY, scheduleKind.interval.toMatchString())
|
notificationIntent.putExtra(TimedNotificationPublisher.CRON_KEY, schedule.interval.toMatchString())
|
||||||
pendingIntent =
|
pendingIntent =
|
||||||
PendingIntent.getBroadcast(context, request.id, notificationIntent, flags)
|
PendingIntent.getBroadcast(context, request.id, notificationIntent, flags)
|
||||||
setExactIfPossible(alarmManager, schedule, trigger, pendingIntent)
|
setExactIfPossible(alarmManager, schedule, trigger, pendingIntent)
|
||||||
@@ -352,8 +352,8 @@ class TauriNotificationManager(
|
|||||||
"notification " + request.id + " will next fire at " + sdf.format(Date(trigger))
|
"notification " + request.id + " will next fire at " + sdf.format(Date(trigger))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ScheduleKind.Every -> {
|
is NotificationSchedule.Every -> {
|
||||||
val everyInterval = getIntervalTime(scheduleKind.interval, scheduleKind.count)
|
val everyInterval = getIntervalTime(schedule.interval, schedule.count)
|
||||||
val startTime: Long = Date().time + everyInterval
|
val startTime: Long = Date().time + everyInterval
|
||||||
alarmManager.setRepeating(AlarmManager.RTC, startTime, everyInterval, pendingIntent)
|
alarmManager.setRepeating(AlarmManager.RTC, startTime, everyInterval, pendingIntent)
|
||||||
}
|
}
|
||||||
@@ -369,13 +369,13 @@ class TauriNotificationManager(
|
|||||||
pendingIntent: PendingIntent
|
pendingIntent: PendingIntent
|
||||||
) {
|
) {
|
||||||
if (SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
|
if (SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
|
||||||
if (SDK_INT >= Build.VERSION_CODES.M && schedule.whileIdle) {
|
if (SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) {
|
||||||
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, trigger, pendingIntent)
|
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, trigger, pendingIntent)
|
||||||
} else {
|
} else {
|
||||||
alarmManager[AlarmManager.RTC, trigger] = pendingIntent
|
alarmManager[AlarmManager.RTC, trigger] = pendingIntent
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (SDK_INT >= Build.VERSION_CODES.M && schedule.whileIdle) {
|
if (SDK_INT >= Build.VERSION_CODES.M && schedule.allowWhileIdle()) {
|
||||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, trigger, pendingIntent)
|
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, trigger, pendingIntent)
|
||||||
} else {
|
} else {
|
||||||
alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent)
|
alarmManager.setExact(AlarmManager.RTC, trigger, pendingIntent)
|
||||||
@@ -426,7 +426,7 @@ class TauriNotificationManager(
|
|||||||
private fun getDefaultSound(context: Context): Int {
|
private fun getDefaultSound(context: Context): Int {
|
||||||
if (defaultSoundID != AssetUtils.RESOURCE_ID_ZERO_VALUE) return defaultSoundID
|
if (defaultSoundID != AssetUtils.RESOURCE_ID_ZERO_VALUE) return defaultSoundID
|
||||||
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
||||||
val soundConfigResourceName = AssetUtils.getResourceBaseName(config.getString("sound"))
|
val soundConfigResourceName = AssetUtils.getResourceBaseName(config?.sound)
|
||||||
if (soundConfigResourceName != null) {
|
if (soundConfigResourceName != null) {
|
||||||
resId = AssetUtils.getResourceID(context, soundConfigResourceName, "raw")
|
resId = AssetUtils.getResourceID(context, soundConfigResourceName, "raw")
|
||||||
}
|
}
|
||||||
@@ -437,7 +437,7 @@ class TauriNotificationManager(
|
|||||||
private fun getDefaultSmallIcon(context: Context): Int {
|
private fun getDefaultSmallIcon(context: Context): Int {
|
||||||
if (defaultSmallIconID != AssetUtils.RESOURCE_ID_ZERO_VALUE) return defaultSmallIconID
|
if (defaultSmallIconID != AssetUtils.RESOURCE_ID_ZERO_VALUE) return defaultSmallIconID
|
||||||
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
var resId: Int = AssetUtils.RESOURCE_ID_ZERO_VALUE
|
||||||
val smallIconConfigResourceName = AssetUtils.getResourceBaseName(config.getString("icon"))
|
val smallIconConfigResourceName = AssetUtils.getResourceBaseName(config?.icon)
|
||||||
if (smallIconConfigResourceName != null) {
|
if (smallIconConfigResourceName != null) {
|
||||||
resId = AssetUtils.getResourceID(context, smallIconConfigResourceName, "drawable")
|
resId = AssetUtils.getResourceID(context, smallIconConfigResourceName, "drawable")
|
||||||
}
|
}
|
||||||
@@ -460,7 +460,7 @@ class NotificationDismissReceiver : BroadcastReceiver() {
|
|||||||
val isRemovable =
|
val isRemovable =
|
||||||
intent.getBooleanExtra(NOTIFICATION_IS_REMOVABLE_KEY, true)
|
intent.getBooleanExtra(NOTIFICATION_IS_REMOVABLE_KEY, true)
|
||||||
if (isRemovable) {
|
if (isRemovable) {
|
||||||
val notificationStorage = NotificationStorage(context)
|
val notificationStorage = NotificationStorage(context, ObjectMapper())
|
||||||
notificationStorage.deleteNotification(intExtra.toString())
|
notificationStorage.deleteNotification(intExtra.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,11 +486,13 @@ class TimedNotificationPublisher : BroadcastReceiver() {
|
|||||||
if (id == Int.MIN_VALUE) {
|
if (id == Int.MIN_VALUE) {
|
||||||
Logger.error(Logger.tags("Notification"), "No valid id supplied", null)
|
Logger.error(Logger.tags("Notification"), "No valid id supplied", null)
|
||||||
}
|
}
|
||||||
val storage = NotificationStorage(context)
|
val storage = NotificationStorage(context, ObjectMapper())
|
||||||
val notificationJson = storage.getSavedNotificationAsJSObject(id.toString())
|
|
||||||
if (notificationJson != null) {
|
val savedNotification = storage.getSavedNotification(id.toString())
|
||||||
NotificationPlugin.triggerNotification(notificationJson)
|
if (savedNotification != null) {
|
||||||
|
NotificationPlugin.triggerNotification(savedNotification)
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager.notify(id, notification)
|
notificationManager.notify(id, notification)
|
||||||
if (!rescheduleNotificationIfNeeded(context, intent, id)) {
|
if (!rescheduleNotificationIfNeeded(context, intent, id)) {
|
||||||
storage.deleteNotification(id.toString())
|
storage.deleteNotification(id.toString())
|
||||||
@@ -545,19 +547,19 @@ class LocalNotificationRestoreReceiver : BroadcastReceiver() {
|
|||||||
)
|
)
|
||||||
if (um == null || !um.isUserUnlocked) return
|
if (um == null || !um.isUserUnlocked) return
|
||||||
}
|
}
|
||||||
val storage = NotificationStorage(context)
|
val storage = NotificationStorage(context, ObjectMapper())
|
||||||
val ids = storage.getSavedNotificationIds()
|
val ids = storage.getSavedNotificationIds()
|
||||||
val notifications = mutableListOf<Notification>()
|
val notifications = mutableListOf<Notification>()
|
||||||
val updatedNotifications = mutableListOf<Notification>()
|
val updatedNotifications = mutableListOf<Notification>()
|
||||||
for (id in ids) {
|
for (id in ids) {
|
||||||
val notification = storage.getSavedNotification(id) ?: continue
|
val notification = storage.getSavedNotification(id) ?: continue
|
||||||
val schedule = notification.schedule
|
val schedule = notification.schedule
|
||||||
if (schedule != null && schedule.kind is ScheduleKind.At) {
|
if (schedule != null && schedule is NotificationSchedule.At) {
|
||||||
val at: Date = schedule.kind.date
|
val at: Date = schedule.date
|
||||||
if (at.before(Date())) {
|
if (at.before(Date())) {
|
||||||
// modify the scheduled date in order to show notifications that would have been delivered while device was off.
|
// modify the scheduled date in order to show notifications that would have been delivered while device was off.
|
||||||
val newDateTime = Date().time + 15 * 1000
|
val newDateTime = Date().time + 15 * 1000
|
||||||
schedule.kind.date = Date(newDateTime)
|
schedule.date = Date(newDateTime)
|
||||||
updatedNotifications.add(notification)
|
updatedNotifications.add(notification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -567,7 +569,13 @@ class LocalNotificationRestoreReceiver : BroadcastReceiver() {
|
|||||||
storage.appendNotifications(updatedNotifications)
|
storage.appendNotifications(updatedNotifications)
|
||||||
}
|
}
|
||||||
|
|
||||||
val notificationManager = TauriNotificationManager(storage, null, context, PluginManager.loadConfig(context, "notification"))
|
var config: PluginConfig? = null
|
||||||
|
try {
|
||||||
|
config = PluginManager.loadConfig(context, "notification", PluginConfig::class.java)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
val notificationManager = TauriNotificationManager(storage, null, context, config)
|
||||||
notificationManager.schedule(notifications)
|
notificationManager.schedule(notifications)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fn main() {
|
|||||||
{
|
{
|
||||||
println!("{error:#}");
|
println!("{error:#}");
|
||||||
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
// when building documentation for Android the plugin build result is irrelevant to the crate itself
|
||||||
if !(cfg!(feature = "dox") && std::env::var("TARGET").unwrap().contains("android")) {
|
if !(cfg!(docsrs) && std::env::var("TARGET").unwrap().contains("android")) {
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,57 +150,62 @@ type ScheduleInterval = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum ScheduleEvery {
|
enum ScheduleEvery {
|
||||||
Year = "Year",
|
Year = "year",
|
||||||
Month = "Month",
|
Month = "month",
|
||||||
TwoWeeks = "TwoWeeks",
|
TwoWeeks = "twoWeeks",
|
||||||
Week = "Week",
|
Week = "week",
|
||||||
Day = "Day",
|
Day = "day",
|
||||||
Hour = "Hour",
|
Hour = "hour",
|
||||||
Minute = "Minute",
|
Minute = "minute",
|
||||||
/**
|
/**
|
||||||
* Not supported on iOS.
|
* Not supported on iOS.
|
||||||
*/
|
*/
|
||||||
Second = "Second",
|
Second = "second",
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScheduleData =
|
type ScheduleData =
|
||||||
| {
|
| {
|
||||||
kind: "At";
|
at: {
|
||||||
data: {
|
|
||||||
date: Date;
|
date: Date;
|
||||||
repeating: boolean;
|
repeating: boolean;
|
||||||
|
allowWhileIdle: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: "Interval";
|
interval: {
|
||||||
data: ScheduleInterval;
|
interval: ScheduleInterval;
|
||||||
|
allowWhileIdle: boolean;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: "Every";
|
every: {
|
||||||
data: {
|
|
||||||
interval: ScheduleEvery;
|
interval: ScheduleEvery;
|
||||||
|
count: number;
|
||||||
|
allowWhileIdle: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Schedule {
|
class Schedule {
|
||||||
kind: string;
|
schedule: ScheduleData;
|
||||||
data: unknown;
|
|
||||||
|
|
||||||
private constructor(schedule: ScheduleData) {
|
private constructor(schedule: ScheduleData) {
|
||||||
this.kind = schedule.kind;
|
this.schedule = schedule;
|
||||||
this.data = schedule.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static at(date: Date, repeating = false) {
|
toJSON(): string {
|
||||||
return new Schedule({ kind: "At", data: { date, repeating } });
|
return JSON.stringify(this.schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
static interval(interval: ScheduleInterval) {
|
static at(date: Date, repeating = false, allowWhileIdle = false) {
|
||||||
return new Schedule({ kind: "Interval", data: interval });
|
return new Schedule({ at: { date, repeating, allowWhileIdle } });
|
||||||
}
|
}
|
||||||
|
|
||||||
static every(kind: ScheduleEvery) {
|
static interval(interval: ScheduleInterval, allowWhileIdle = false) {
|
||||||
return new Schedule({ kind: "Every", data: { interval: kind } });
|
return new Schedule({ interval: { interval, allowWhileIdle } });
|
||||||
|
}
|
||||||
|
|
||||||
|
static every(kind: ScheduleEvery, count: number, allowWhileIdle = false) {
|
||||||
|
return new Schedule({ every: { interval: kind, count, allowWhileIdle } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +466,9 @@ async function active(): Promise<ActiveNotification[]> {
|
|||||||
*
|
*
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
async function removeActive(notifications: number[]): Promise<void> {
|
async function removeActive(
|
||||||
|
notifications: { id: number; tag?: string }[],
|
||||||
|
): Promise<void> {
|
||||||
return invoke("plugin:notification|remove_active", { notifications });
|
return invoke("plugin:notification|remove_active", { notifications });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,7 +490,7 @@ async function removeAllActive(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all active notifications.
|
* Creates a notification channel.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
@@ -537,7 +544,7 @@ async function removeChannel(id: string): Promise<void> {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
async function channels(): Promise<Channel[]> {
|
async function channels(): Promise<Channel[]> {
|
||||||
return invoke("plugin:notification|getActive");
|
return invoke("plugin:notification|listChannels");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onNotificationReceived(
|
async function onNotificationReceived(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// swift-tools-version:5.3
|
// swift-tools-version:5.5
|
||||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|||||||
@@ -6,12 +6,7 @@ import Tauri
|
|||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
enum NotificationError: LocalizedError {
|
enum NotificationError: LocalizedError {
|
||||||
case contentNoId
|
|
||||||
case contentNoTitle
|
|
||||||
case contentNoBody
|
|
||||||
case triggerRepeatIntervalTooShort
|
case triggerRepeatIntervalTooShort
|
||||||
case attachmentNoId
|
|
||||||
case attachmentNoUrl
|
|
||||||
case attachmentFileNotFound(path: String)
|
case attachmentFileNotFound(path: String)
|
||||||
case attachmentUnableToCreate(String)
|
case attachmentUnableToCreate(String)
|
||||||
case pastScheduledTime
|
case pastScheduledTime
|
||||||
@@ -19,18 +14,8 @@ enum NotificationError: LocalizedError {
|
|||||||
|
|
||||||
var errorDescription: String? {
|
var errorDescription: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .contentNoId:
|
|
||||||
return "Missing notification identifier"
|
|
||||||
case .contentNoTitle:
|
|
||||||
return "Missing notification title"
|
|
||||||
case .contentNoBody:
|
|
||||||
return "Missing notification body"
|
|
||||||
case .triggerRepeatIntervalTooShort:
|
case .triggerRepeatIntervalTooShort:
|
||||||
return "Schedule interval too short, must be a least 1 minute"
|
return "Schedule interval too short, must be a least 1 minute"
|
||||||
case .attachmentNoId:
|
|
||||||
return "Missing attachment identifier"
|
|
||||||
case .attachmentNoUrl:
|
|
||||||
return "Missing attachment URL"
|
|
||||||
case .attachmentFileNotFound(let path):
|
case .attachmentFileNotFound(let path):
|
||||||
return "Unable to find file \(path) for attachment"
|
return "Unable to find file \(path) for attachment"
|
||||||
case .attachmentUnableToCreate(let error):
|
case .attachmentUnableToCreate(let error):
|
||||||
@@ -43,69 +28,56 @@ enum NotificationError: LocalizedError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeNotificationContent(_ notification: JSObject) throws -> UNNotificationContent {
|
func makeNotificationContent(_ notification: Notification) throws -> UNNotificationContent {
|
||||||
guard let title = notification["title"] as? String else {
|
|
||||||
throw NotificationError.contentNoTitle
|
|
||||||
}
|
|
||||||
guard let body = notification["body"] as? String else {
|
|
||||||
throw NotificationError.contentNoBody
|
|
||||||
}
|
|
||||||
|
|
||||||
let extra = notification["extra"] as? JSObject ?? [:]
|
|
||||||
let schedule = notification["schedule"] as? JSObject ?? [:]
|
|
||||||
let content = UNMutableNotificationContent()
|
let content = UNMutableNotificationContent()
|
||||||
content.title = NSString.localizedUserNotificationString(forKey: title, arguments: nil)
|
content.title = NSString.localizedUserNotificationString(
|
||||||
|
forKey: notification.title, arguments: nil)
|
||||||
content.body = NSString.localizedUserNotificationString(
|
content.body = NSString.localizedUserNotificationString(
|
||||||
forKey: body,
|
forKey: notification.body,
|
||||||
arguments: nil)
|
arguments: nil)
|
||||||
|
|
||||||
content.userInfo = [
|
content.userInfo = [
|
||||||
"__EXTRA__": extra,
|
"__EXTRA__": notification.extra as Any,
|
||||||
"__SCHEDULE__": schedule,
|
"__SCHEDULE__": notification.schedule as Any,
|
||||||
]
|
]
|
||||||
|
|
||||||
if let actionTypeId = notification["actionTypeId"] as? String {
|
if let actionTypeId = notification.actionTypeId {
|
||||||
content.categoryIdentifier = actionTypeId
|
content.categoryIdentifier = actionTypeId
|
||||||
}
|
}
|
||||||
|
|
||||||
if let threadIdentifier = notification["group"] as? String {
|
if let threadIdentifier = notification.group {
|
||||||
content.threadIdentifier = threadIdentifier
|
content.threadIdentifier = threadIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
if let summaryArgument = notification["summary"] as? String {
|
if let summaryArgument = notification.summary {
|
||||||
content.summaryArgument = summaryArgument
|
content.summaryArgument = summaryArgument
|
||||||
}
|
}
|
||||||
|
|
||||||
if let sound = notification["sound"] as? String {
|
if let sound = notification.sound {
|
||||||
content.sound = UNNotificationSound(named: UNNotificationSoundName(sound))
|
content.sound = UNNotificationSound(named: UNNotificationSoundName(sound))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let attachments = notification["attachments"] as? [JSObject] {
|
if let attachments = notification.attachments {
|
||||||
content.attachments = try makeAttachments(attachments)
|
content.attachments = try makeAttachments(attachments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAttachments(_ attachments: [JSObject]) throws -> [UNNotificationAttachment] {
|
func makeAttachments(_ attachments: [NotificationAttachment]) throws -> [UNNotificationAttachment] {
|
||||||
var createdAttachments = [UNNotificationAttachment]()
|
var createdAttachments = [UNNotificationAttachment]()
|
||||||
|
|
||||||
for attachment in attachments {
|
for attachment in attachments {
|
||||||
guard let id = attachment["id"] as? String else {
|
|
||||||
throw NotificationError.attachmentNoId
|
guard let urlObject = makeAttachmentUrl(attachment.url) else {
|
||||||
}
|
throw NotificationError.attachmentFileNotFound(path: attachment.url)
|
||||||
guard let url = attachment["url"] as? String else {
|
|
||||||
throw NotificationError.attachmentNoUrl
|
|
||||||
}
|
|
||||||
guard let urlObject = makeAttachmentUrl(url) else {
|
|
||||||
throw NotificationError.attachmentFileNotFound(path: url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = attachment["options"] as? JSObject ?? [:]
|
let options = attachment.options != nil ? makeAttachmentOptions(attachment.options!) : nil
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let newAttachment = try UNNotificationAttachment(
|
let newAttachment = try UNNotificationAttachment(
|
||||||
identifier: id, url: urlObject, options: makeAttachmentOptions(options))
|
identifier: attachment.id, url: urlObject, options: options)
|
||||||
createdAttachments.append(newAttachment)
|
createdAttachments.append(newAttachment)
|
||||||
} catch {
|
} catch {
|
||||||
throw NotificationError.attachmentUnableToCreate(error.localizedDescription)
|
throw NotificationError.attachmentUnableToCreate(error.localizedDescription)
|
||||||
@@ -119,50 +91,37 @@ func makeAttachmentUrl(_ path: String) -> URL? {
|
|||||||
return URL(string: path)
|
return URL(string: path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAttachmentOptions(_ options: JSObject) -> JSObject {
|
func makeAttachmentOptions(_ options: NotificationAttachmentOptions) -> [AnyHashable: Any] {
|
||||||
var opts: JSObject = [:]
|
var opts: [AnyHashable: Any] = [:]
|
||||||
|
|
||||||
if let iosUNNotificationAttachmentOptionsTypeHintKey = options[
|
if let value = options.iosUNNotificationAttachmentOptionsTypeHintKey {
|
||||||
"iosUNNotificationAttachmentOptionsTypeHintKey"] as? String
|
opts[UNNotificationAttachmentOptionsTypeHintKey] = value
|
||||||
{
|
|
||||||
opts[UNNotificationAttachmentOptionsTypeHintKey] = iosUNNotificationAttachmentOptionsTypeHintKey
|
|
||||||
}
|
}
|
||||||
if let iosUNNotificationAttachmentOptionsThumbnailHiddenKey = options[
|
if let value = options.iosUNNotificationAttachmentOptionsThumbnailHiddenKey {
|
||||||
"iosUNNotificationAttachmentOptionsThumbnailHiddenKey"] as? String
|
opts[UNNotificationAttachmentOptionsThumbnailHiddenKey] = value
|
||||||
{
|
|
||||||
opts[UNNotificationAttachmentOptionsThumbnailHiddenKey] =
|
|
||||||
iosUNNotificationAttachmentOptionsThumbnailHiddenKey
|
|
||||||
}
|
}
|
||||||
if let iosUNNotificationAttachmentOptionsThumbnailClippingRectKey = options[
|
if let value = options.iosUNNotificationAttachmentOptionsThumbnailClippingRectKey {
|
||||||
"iosUNNotificationAttachmentOptionsThumbnailClippingRectKey"] as? String
|
opts[UNNotificationAttachmentOptionsThumbnailClippingRectKey] = value
|
||||||
{
|
|
||||||
opts[UNNotificationAttachmentOptionsThumbnailClippingRectKey] =
|
|
||||||
iosUNNotificationAttachmentOptionsThumbnailClippingRectKey
|
|
||||||
}
|
}
|
||||||
if let iosUNNotificationAttachmentOptionsThumbnailTimeKey = options[
|
if let value = options
|
||||||
"iosUNNotificationAttachmentOptionsThumbnailTimeKey"] as? String
|
.iosUNNotificationAttachmentOptionsThumbnailTimeKey
|
||||||
|
|
||||||
{
|
{
|
||||||
opts[UNNotificationAttachmentOptionsThumbnailTimeKey] =
|
opts[UNNotificationAttachmentOptionsThumbnailTimeKey] = value
|
||||||
iosUNNotificationAttachmentOptionsThumbnailTimeKey
|
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleScheduledNotification(_ schedule: JSObject) throws
|
func handleScheduledNotification(_ schedule: NotificationSchedule) throws
|
||||||
-> UNNotificationTrigger?
|
-> UNNotificationTrigger?
|
||||||
{
|
{
|
||||||
let kind = schedule["kind"] as? String ?? ""
|
switch schedule {
|
||||||
let payload = schedule["data"] as? JSObject ?? [:]
|
case .at(let date, let repeating):
|
||||||
switch kind {
|
|
||||||
case "At":
|
|
||||||
let date = payload["date"] as? String ?? ""
|
|
||||||
let dateFormatter = DateFormatter()
|
let dateFormatter = DateFormatter()
|
||||||
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
||||||
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
||||||
|
|
||||||
if let at = dateFormatter.date(from: date) {
|
if let at = dateFormatter.date(from: date) {
|
||||||
let repeats = payload["repeats"] as? Bool ?? false
|
|
||||||
|
|
||||||
let dateInfo = Calendar.current.dateComponents(in: TimeZone.current, from: at)
|
let dateInfo = Calendar.current.dateComponents(in: TimeZone.current, from: at)
|
||||||
|
|
||||||
if dateInfo.date! < Date() {
|
if dateInfo.date! < Date() {
|
||||||
@@ -172,23 +131,20 @@ func handleScheduledNotification(_ schedule: JSObject) throws
|
|||||||
let dateInterval = DateInterval(start: Date(), end: dateInfo.date!)
|
let dateInterval = DateInterval(start: Date(), end: dateInfo.date!)
|
||||||
|
|
||||||
// Notifications that repeat have to be at least a minute between each other
|
// Notifications that repeat have to be at least a minute between each other
|
||||||
if repeats && dateInterval.duration < 60 {
|
if repeating && dateInterval.duration < 60 {
|
||||||
throw NotificationError.triggerRepeatIntervalTooShort
|
throw NotificationError.triggerRepeatIntervalTooShort
|
||||||
}
|
}
|
||||||
|
|
||||||
return UNTimeIntervalNotificationTrigger(
|
return UNTimeIntervalNotificationTrigger(
|
||||||
timeInterval: dateInterval.duration, repeats: repeats)
|
timeInterval: dateInterval.duration, repeats: repeating)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw NotificationError.invalidDate(date)
|
throw NotificationError.invalidDate(date)
|
||||||
}
|
}
|
||||||
case "Interval":
|
case .interval(let interval):
|
||||||
let dateComponents = getDateComponents(payload)
|
let dateComponents = getDateComponents(interval)
|
||||||
return UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
|
return UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
|
||||||
case "Every":
|
case .every(let interval, let count):
|
||||||
let interval = payload["interval"] as? String ?? ""
|
|
||||||
let count = schedule["count"] as? Int ?? 1
|
|
||||||
|
|
||||||
if let repeatDateInterval = getRepeatDateInterval(interval, count) {
|
if let repeatDateInterval = getRepeatDateInterval(interval, count) {
|
||||||
// Notifications that repeat have to be at least a minute between each other
|
// Notifications that repeat have to be at least a minute between each other
|
||||||
if repeatDateInterval.duration < 60 {
|
if repeatDateInterval.duration < 60 {
|
||||||
@@ -198,9 +154,6 @@ func handleScheduledNotification(_ schedule: JSObject) throws
|
|||||||
return UNTimeIntervalNotificationTrigger(
|
return UNTimeIntervalNotificationTrigger(
|
||||||
timeInterval: repeatDateInterval.duration, repeats: true)
|
timeInterval: repeatDateInterval.duration, repeats: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -209,30 +162,30 @@ func handleScheduledNotification(_ schedule: JSObject) throws
|
|||||||
/// Given our schedule format, return a DateComponents object
|
/// Given our schedule format, return a DateComponents object
|
||||||
/// that only contains the components passed in.
|
/// that only contains the components passed in.
|
||||||
|
|
||||||
func getDateComponents(_ at: JSObject) -> DateComponents {
|
func getDateComponents(_ at: ScheduleInterval) -> DateComponents {
|
||||||
// var dateInfo = Calendar.current.dateComponents(in: TimeZone.current, from: Date())
|
// var dateInfo = Calendar.current.dateComponents(in: TimeZone.current, from: Date())
|
||||||
// dateInfo.calendar = Calendar.current
|
// dateInfo.calendar = Calendar.current
|
||||||
var dateInfo = DateComponents()
|
var dateInfo = DateComponents()
|
||||||
|
|
||||||
if let year = at["year"] as? Int {
|
if let year = at.year {
|
||||||
dateInfo.year = year
|
dateInfo.year = year
|
||||||
}
|
}
|
||||||
if let month = at["month"] as? Int {
|
if let month = at.month {
|
||||||
dateInfo.month = month
|
dateInfo.month = month
|
||||||
}
|
}
|
||||||
if let day = at["day"] as? Int {
|
if let day = at.day {
|
||||||
dateInfo.day = day
|
dateInfo.day = day
|
||||||
}
|
}
|
||||||
if let hour = at["hour"] as? Int {
|
if let hour = at.hour {
|
||||||
dateInfo.hour = hour
|
dateInfo.hour = hour
|
||||||
}
|
}
|
||||||
if let minute = at["minute"] as? Int {
|
if let minute = at.minute {
|
||||||
dateInfo.minute = minute
|
dateInfo.minute = minute
|
||||||
}
|
}
|
||||||
if let second = at["second"] as? Int {
|
if let second = at.second {
|
||||||
dateInfo.second = second
|
dateInfo.second = second
|
||||||
}
|
}
|
||||||
if let weekday = at["weekday"] as? Int {
|
if let weekday = at.weekday {
|
||||||
dateInfo.weekday = weekday
|
dateInfo.weekday = weekday
|
||||||
}
|
}
|
||||||
return dateInfo
|
return dateInfo
|
||||||
@@ -242,35 +195,33 @@ func getDateComponents(_ at: JSObject) -> DateComponents {
|
|||||||
/// interval and today. For example, if every is "month", then we
|
/// interval and today. For example, if every is "month", then we
|
||||||
/// return the interval between today and a month from today.
|
/// return the interval between today and a month from today.
|
||||||
|
|
||||||
func getRepeatDateInterval(_ every: String, _ count: Int) -> DateInterval? {
|
func getRepeatDateInterval(_ every: ScheduleEveryKind, _ count: Int) -> DateInterval? {
|
||||||
let cal = Calendar.current
|
let cal = Calendar.current
|
||||||
let now = Date()
|
let now = Date()
|
||||||
switch every {
|
switch every {
|
||||||
case "Year":
|
case .year:
|
||||||
let newDate = cal.date(byAdding: .year, value: count, to: now)!
|
let newDate = cal.date(byAdding: .year, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Month":
|
case .month:
|
||||||
let newDate = cal.date(byAdding: .month, value: count, to: now)!
|
let newDate = cal.date(byAdding: .month, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "TwoWeeks":
|
case .twoWeeks:
|
||||||
let newDate = cal.date(byAdding: .weekOfYear, value: 2 * count, to: now)!
|
let newDate = cal.date(byAdding: .weekOfYear, value: 2 * count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Week":
|
case .week:
|
||||||
let newDate = cal.date(byAdding: .weekOfYear, value: count, to: now)!
|
let newDate = cal.date(byAdding: .weekOfYear, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Day":
|
case .day:
|
||||||
let newDate = cal.date(byAdding: .day, value: count, to: now)!
|
let newDate = cal.date(byAdding: .day, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Hour":
|
case .hour:
|
||||||
let newDate = cal.date(byAdding: .hour, value: count, to: now)!
|
let newDate = cal.date(byAdding: .hour, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Minute":
|
case .minute:
|
||||||
let newDate = cal.date(byAdding: .minute, value: count, to: now)!
|
let newDate = cal.date(byAdding: .minute, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
case "Second":
|
case .second:
|
||||||
let newDate = cal.date(byAdding: .second, value: count, to: now)!
|
let newDate = cal.date(byAdding: .second, value: count, to: now)!
|
||||||
return DateInterval(start: now, end: newDate)
|
return DateInterval(start: now, end: newDate)
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,21 +5,7 @@
|
|||||||
import Tauri
|
import Tauri
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
enum CategoryError: LocalizedError {
|
internal func makeCategories(_ actionTypes: [ActionType]) {
|
||||||
case noId
|
|
||||||
case noActionId
|
|
||||||
|
|
||||||
var errorDescription: String? {
|
|
||||||
switch self {
|
|
||||||
case .noId:
|
|
||||||
return "Action type `id` missing"
|
|
||||||
case .noActionId:
|
|
||||||
return "Action `id` missing"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func makeCategories(_ actionTypes: [JSObject]) throws {
|
|
||||||
var createdCategories = [UNNotificationCategory]()
|
var createdCategories = [UNNotificationCategory]()
|
||||||
|
|
||||||
let generalCategory = UNNotificationCategory(
|
let generalCategory = UNNotificationCategory(
|
||||||
@@ -30,22 +16,16 @@ public func makeCategories(_ actionTypes: [JSObject]) throws {
|
|||||||
|
|
||||||
createdCategories.append(generalCategory)
|
createdCategories.append(generalCategory)
|
||||||
for type in actionTypes {
|
for type in actionTypes {
|
||||||
guard let id = type["id"] as? String else {
|
let newActions = makeActions(type.actions)
|
||||||
throw CategoryError.noId
|
|
||||||
}
|
|
||||||
let hiddenBodyPlaceholder = type["hiddenPreviewsBodyPlaceholder"] as? String ?? ""
|
|
||||||
let actions = type["actions"] as? [JSObject] ?? []
|
|
||||||
|
|
||||||
let newActions = try makeActions(actions)
|
|
||||||
|
|
||||||
// Create the custom actions for the TIMER_EXPIRED category.
|
// Create the custom actions for the TIMER_EXPIRED category.
|
||||||
var newCategory: UNNotificationCategory?
|
var newCategory: UNNotificationCategory?
|
||||||
|
|
||||||
newCategory = UNNotificationCategory(
|
newCategory = UNNotificationCategory(
|
||||||
identifier: id,
|
identifier: type.id,
|
||||||
actions: newActions,
|
actions: newActions,
|
||||||
intentIdentifiers: [],
|
intentIdentifiers: [],
|
||||||
hiddenPreviewsBodyPlaceholder: hiddenBodyPlaceholder,
|
hiddenPreviewsBodyPlaceholder: type.hiddenBodyPlaceholder ?? "",
|
||||||
options: makeCategoryOptions(type))
|
options: makeCategoryOptions(type))
|
||||||
|
|
||||||
createdCategories.append(newCategory!)
|
createdCategories.append(newCategory!)
|
||||||
@@ -55,37 +35,28 @@ public func makeCategories(_ actionTypes: [JSObject]) throws {
|
|||||||
center.setNotificationCategories(Set(createdCategories))
|
center.setNotificationCategories(Set(createdCategories))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeActions(_ actions: [JSObject]) throws -> [UNNotificationAction] {
|
func makeActions(_ actions: [Action]) -> [UNNotificationAction] {
|
||||||
var createdActions = [UNNotificationAction]()
|
var createdActions = [UNNotificationAction]()
|
||||||
|
|
||||||
for action in actions {
|
for action in actions {
|
||||||
guard let id = action["id"] as? String else {
|
|
||||||
throw CategoryError.noActionId
|
|
||||||
}
|
|
||||||
let title = action["title"] as? String ?? ""
|
|
||||||
let input = action["input"] as? Bool ?? false
|
|
||||||
|
|
||||||
var newAction: UNNotificationAction
|
var newAction: UNNotificationAction
|
||||||
if input {
|
if action.input {
|
||||||
let inputButtonTitle = action["inputButtonTitle"] as? String
|
if action.inputButtonTitle != nil {
|
||||||
let inputPlaceholder = action["inputPlaceholder"] as? String ?? ""
|
|
||||||
|
|
||||||
if inputButtonTitle != nil {
|
|
||||||
newAction = UNTextInputNotificationAction(
|
newAction = UNTextInputNotificationAction(
|
||||||
identifier: id,
|
identifier: action.id,
|
||||||
title: title,
|
title: action.title,
|
||||||
options: makeActionOptions(action),
|
options: makeActionOptions(action),
|
||||||
textInputButtonTitle: inputButtonTitle!,
|
textInputButtonTitle: action.inputButtonTitle ?? "",
|
||||||
textInputPlaceholder: inputPlaceholder)
|
textInputPlaceholder: action.inputPlaceholder ?? "")
|
||||||
} else {
|
} else {
|
||||||
newAction = UNTextInputNotificationAction(
|
newAction = UNTextInputNotificationAction(
|
||||||
identifier: id, title: title, options: makeActionOptions(action))
|
identifier: action.id, title: action.title, options: makeActionOptions(action))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create the custom actions for the TIMER_EXPIRED category.
|
// Create the custom actions for the TIMER_EXPIRED category.
|
||||||
newAction = UNNotificationAction(
|
newAction = UNNotificationAction(
|
||||||
identifier: id,
|
identifier: action.id,
|
||||||
title: title,
|
title: action.title,
|
||||||
options: makeActionOptions(action))
|
options: makeActionOptions(action))
|
||||||
}
|
}
|
||||||
createdActions.append(newAction)
|
createdActions.append(newAction)
|
||||||
@@ -94,40 +65,31 @@ func makeActions(_ actions: [JSObject]) throws -> [UNNotificationAction] {
|
|||||||
return createdActions
|
return createdActions
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeActionOptions(_ action: JSObject) -> UNNotificationActionOptions {
|
func makeActionOptions(_ action: Action) -> UNNotificationActionOptions {
|
||||||
let foreground = action["foreground"] as? Bool ?? false
|
if action.foreground {
|
||||||
let destructive = action["destructive"] as? Bool ?? false
|
|
||||||
let requiresAuthentication = action["requiresAuthentication"] as? Bool ?? false
|
|
||||||
|
|
||||||
if foreground {
|
|
||||||
return .foreground
|
return .foreground
|
||||||
}
|
}
|
||||||
if destructive {
|
if action.destructive {
|
||||||
return .destructive
|
return .destructive
|
||||||
}
|
}
|
||||||
if requiresAuthentication {
|
if action.requiresAuthentication {
|
||||||
return .authenticationRequired
|
return .authenticationRequired
|
||||||
}
|
}
|
||||||
return UNNotificationActionOptions(rawValue: 0)
|
return UNNotificationActionOptions(rawValue: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCategoryOptions(_ type: JSObject) -> UNNotificationCategoryOptions {
|
func makeCategoryOptions(_ type: ActionType) -> UNNotificationCategoryOptions {
|
||||||
let customDismiss = type["customDismissAction"] as? Bool ?? false
|
if type.customDismissAction {
|
||||||
let carPlay = type["allowInCarPlay"] as? Bool ?? false
|
|
||||||
let hiddenPreviewsShowTitle = type["hiddenPreviewsShowTitle"] as? Bool ?? false
|
|
||||||
let hiddenPreviewsShowSubtitle = type["hiddenPreviewsShowSubtitle"] as? Bool ?? false
|
|
||||||
|
|
||||||
if customDismiss {
|
|
||||||
return .customDismissAction
|
return .customDismissAction
|
||||||
}
|
}
|
||||||
if carPlay {
|
if type.allowInCarPlay {
|
||||||
return .allowInCarPlay
|
return .allowInCarPlay
|
||||||
}
|
}
|
||||||
|
|
||||||
if hiddenPreviewsShowTitle {
|
if type.hiddenPreviewsShowTitle {
|
||||||
return .hiddenPreviewsShowTitle
|
return .hiddenPreviewsShowTitle
|
||||||
}
|
}
|
||||||
if hiddenPreviewsShowSubtitle {
|
if type.hiddenPreviewsShowSubtitle {
|
||||||
return .hiddenPreviewsShowSubtitle
|
return .hiddenPreviewsShowSubtitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ public class NotificationHandler: NSObject, NotificationHandlerProtocol {
|
|||||||
|
|
||||||
public weak var plugin: Plugin?
|
public weak var plugin: Plugin?
|
||||||
|
|
||||||
private var notificationsMap = [String: JSObject]()
|
private var notificationsMap = [String: Notification]()
|
||||||
|
|
||||||
public func saveNotification(_ key: String, _ notification: JSObject) {
|
internal func saveNotification(_ key: String, _ notification: Notification) {
|
||||||
notificationsMap.updateValue(notification, forKey: key)
|
notificationsMap.updateValue(notification, forKey: key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,12 +30,11 @@ public class NotificationHandler: NSObject, NotificationHandlerProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
|
public func willPresent(notification: UNNotification) -> UNNotificationPresentationOptions {
|
||||||
let notificationData = makeNotificationRequestJSObject(notification.request)
|
let notificationData = toActiveNotification(notification.request)
|
||||||
self.plugin?.trigger("notification", data: notificationData)
|
try? self.plugin?.trigger("notification", data: notificationData)
|
||||||
|
|
||||||
if let options = notificationsMap[notification.request.identifier] {
|
if let options = notificationsMap[notification.request.identifier] {
|
||||||
let silent = options["silent"] as? Bool ?? false
|
if options.silent {
|
||||||
if silent {
|
|
||||||
return UNNotificationPresentationOptions.init(rawValue: 0)
|
return UNNotificationPresentationOptions.init(rawValue: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,73 +47,72 @@ public class NotificationHandler: NSObject, NotificationHandlerProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func didReceive(response: UNNotificationResponse) {
|
public func didReceive(response: UNNotificationResponse) {
|
||||||
var data = JSObject()
|
|
||||||
|
|
||||||
let originalNotificationRequest = response.notification.request
|
let originalNotificationRequest = response.notification.request
|
||||||
let actionId = response.actionIdentifier
|
let actionId = response.actionIdentifier
|
||||||
|
|
||||||
|
var actionIdValue: String
|
||||||
// We turn the two default actions (open/dismiss) into generic strings
|
// We turn the two default actions (open/dismiss) into generic strings
|
||||||
if actionId == UNNotificationDefaultActionIdentifier {
|
if actionId == UNNotificationDefaultActionIdentifier {
|
||||||
data["actionId"] = "tap"
|
actionIdValue = "tap"
|
||||||
} else if actionId == UNNotificationDismissActionIdentifier {
|
} else if actionId == UNNotificationDismissActionIdentifier {
|
||||||
data["actionId"] = "dismiss"
|
actionIdValue = "dismiss"
|
||||||
} else {
|
} else {
|
||||||
data["actionId"] = actionId
|
actionIdValue = actionId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var inputValue: String? = nil
|
||||||
// If the type of action was for an input type, get the value
|
// If the type of action was for an input type, get the value
|
||||||
if let inputType = response as? UNTextInputNotificationResponse {
|
if let inputType = response as? UNTextInputNotificationResponse {
|
||||||
data["inputValue"] = inputType.userText
|
inputValue = inputType.userText
|
||||||
}
|
}
|
||||||
|
|
||||||
data["notification"] = makeNotificationRequestJSObject(originalNotificationRequest)
|
try? self.plugin?.trigger(
|
||||||
|
"actionPerformed",
|
||||||
self.plugin?.trigger("actionPerformed", data: data)
|
data: ReceivedNotification(
|
||||||
|
actionId: actionIdValue,
|
||||||
|
inputValue: inputValue,
|
||||||
|
notification: toActiveNotification(originalNotificationRequest)
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
func toActiveNotification(_ request: UNNotificationRequest) -> ActiveNotification {
|
||||||
* Turn a UNNotificationRequest into a JSObject to return back to the client.
|
let notificationRequest = notificationsMap[request.identifier]!
|
||||||
*/
|
return ActiveNotification(
|
||||||
func makeNotificationRequestJSObject(_ request: UNNotificationRequest) -> JSObject {
|
id: Int(request.identifier) ?? -1,
|
||||||
let notificationRequest = notificationsMap[request.identifier] ?? [:]
|
title: request.content.title,
|
||||||
var notification = makePendingNotificationRequestJSObject(request)
|
body: request.content.body,
|
||||||
notification["sound"] = notificationRequest["sound"] ?? ""
|
sound: notificationRequest.sound ?? "",
|
||||||
notification["actionTypeId"] = request.content.categoryIdentifier
|
actionTypeId: request.content.categoryIdentifier,
|
||||||
notification["attachments"] = notificationRequest["attachments"] ?? [JSObject]()
|
attachments: notificationRequest.attachments
|
||||||
return notification
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePendingNotificationRequestJSObject(_ request: UNNotificationRequest) -> JSObject {
|
func toPendingNotification(_ request: UNNotificationRequest) -> PendingNotification {
|
||||||
var notification: JSObject = [
|
return PendingNotification(
|
||||||
"id": Int(request.identifier) ?? -1,
|
id: Int(request.identifier) ?? -1,
|
||||||
"title": request.content.title,
|
title: request.content.title,
|
||||||
"body": request.content.body,
|
body: request.content.body
|
||||||
]
|
)
|
||||||
|
|
||||||
if let userInfo = JSTypes.coerceDictionaryToJSObject(request.content.userInfo) {
|
|
||||||
var extra = userInfo["__EXTRA__"] as? JSObject ?? userInfo
|
|
||||||
|
|
||||||
// check for any dates and convert them to strings
|
|
||||||
for (key, value) in extra {
|
|
||||||
if let date = value as? Date {
|
|
||||||
let dateString = ISO8601DateFormatter().string(from: date)
|
|
||||||
extra[key] = dateString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notification["extra"] = extra
|
|
||||||
|
|
||||||
if var schedule = userInfo["__SCHEDULE__"] as? JSObject {
|
|
||||||
// convert schedule at date to string
|
|
||||||
if let date = schedule["at"] as? Date {
|
|
||||||
let dateString = ISO8601DateFormatter().string(from: date)
|
|
||||||
schedule["at"] = dateString
|
|
||||||
}
|
|
||||||
|
|
||||||
notification["schedule"] = schedule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return notification
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PendingNotification: Encodable {
|
||||||
|
let id: Int
|
||||||
|
let title: String
|
||||||
|
let body: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ActiveNotification: Encodable {
|
||||||
|
let id: Int
|
||||||
|
let title: String
|
||||||
|
let body: String
|
||||||
|
let sound: String
|
||||||
|
let actionTypeId: String
|
||||||
|
let attachments: [NotificationAttachment]?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReceivedNotification: Encodable {
|
||||||
|
let actionId: String
|
||||||
|
let inputValue: String?
|
||||||
|
let notification: ActiveNotification
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user