mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-24 17:20:51 +02:00
Merge remote-tracking branch 'upstream/v2' into store-rework-2
This commit is contained in:
@@ -10,11 +10,11 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.1",
|
||||
"@tauri-apps/api": "2.0.2",
|
||||
"@tauri-apps/plugin-deep-link": "2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.0.0",
|
||||
"@tauri-apps/cli": "2.0.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.4.7"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.activity.result.ActivityResult
|
||||
import app.tauri.Logger
|
||||
import app.tauri.annotation.ActivityCallback
|
||||
@@ -43,6 +44,7 @@ class MessageOptions {
|
||||
@InvokeArg
|
||||
class SaveFileDialogOptions {
|
||||
var fileName: String? = null
|
||||
lateinit var filters: Array<Filter>
|
||||
}
|
||||
|
||||
@TauriPlugin
|
||||
@@ -57,20 +59,7 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
|
||||
val intent = if (parsedTypes.isNotEmpty()) {
|
||||
val intent = Intent(Intent.ACTION_PICK)
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, parsedTypes)
|
||||
|
||||
var uniqueMimeType = true
|
||||
var mimeKind: String? = null
|
||||
for (mime in parsedTypes) {
|
||||
val kind = mime.split("/")[0]
|
||||
if (mimeKind == null) {
|
||||
mimeKind = kind
|
||||
} else if (mimeKind != kind) {
|
||||
uniqueMimeType = false
|
||||
}
|
||||
}
|
||||
|
||||
intent.type = if (uniqueMimeType) Intent.normalizeMimeType("$mimeKind/*") else "*/*"
|
||||
setIntentMimeTypes(intent, parsedTypes)
|
||||
intent
|
||||
} else {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
@@ -130,12 +119,46 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
private fun parseFiltersOption(filters: Array<Filter>): Array<String> {
|
||||
val mimeTypes = mutableListOf<String>()
|
||||
for (filter in filters) {
|
||||
for (mime in filter.extensions) {
|
||||
mimeTypes.add(if (mime == "text/csv") "text/comma-separated-values" else mime)
|
||||
for (ext in filter.extensions) {
|
||||
if (ext.contains('/')) {
|
||||
mimeTypes.add(if (ext == "text/csv") "text/comma-separated-values" else ext)
|
||||
} else {
|
||||
MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext)?.let {
|
||||
mimeTypes.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mimeTypes.toTypedArray()
|
||||
}
|
||||
|
||||
private fun setIntentMimeTypes(intent: Intent, mimeTypes: Array<String>) {
|
||||
if (mimeTypes.isNotEmpty()) {
|
||||
var uniqueMimeKind = true
|
||||
var mimeKind: String? = null
|
||||
for (mime in mimeTypes) {
|
||||
val kind = mime.split("/")[0]
|
||||
if (mimeKind == null) {
|
||||
mimeKind = kind
|
||||
} else if (mimeKind != kind) {
|
||||
uniqueMimeKind = false
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueMimeKind) {
|
||||
if (mimeTypes.size > 1) {
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
|
||||
intent.type = Intent.normalizeMimeType("$mimeKind/*")
|
||||
} else {
|
||||
intent.type = mimeTypes[0]
|
||||
}
|
||||
} else {
|
||||
intent.type = "*/*"
|
||||
}
|
||||
} else {
|
||||
intent.type = "*/*"
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
fun showMessageDialog(invoke: Invoke) {
|
||||
@@ -187,10 +210,12 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
|
||||
fun saveFileDialog(invoke: Invoke) {
|
||||
try {
|
||||
val args = invoke.parseArgs(SaveFileDialogOptions::class.java)
|
||||
val parsedTypes = parseFiltersOption(args.filters)
|
||||
|
||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||
setIntentMimeTypes(intent, parsedTypes)
|
||||
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
intent.setType("text/plain")
|
||||
intent.putExtra(Intent.EXTRA_TITLE, args.fileName ?: "")
|
||||
startActivityForResult(invoke, intent, "saveFileDialogResult")
|
||||
} catch (ex: Exception) {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc, time::Duration};
|
||||
use std::{future::Future, pin::Pin, str::FromStr, sync::Arc, time::Duration};
|
||||
|
||||
use http::{header, HeaderName, Method, StatusCode};
|
||||
use http::{header, HeaderMap, HeaderName, HeaderValue, Method, StatusCode};
|
||||
use reqwest::{redirect::Policy, NoProxy};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{
|
||||
@@ -176,7 +176,7 @@ pub async fn fetch<R: Runtime>(
|
||||
let ClientConfig {
|
||||
method,
|
||||
url,
|
||||
headers,
|
||||
headers: headers_raw,
|
||||
data,
|
||||
connect_timeout,
|
||||
max_redirections,
|
||||
@@ -185,7 +185,17 @@ pub async fn fetch<R: Runtime>(
|
||||
|
||||
let scheme = url.scheme();
|
||||
let method = Method::from_bytes(method.as_bytes())?;
|
||||
let headers: HashMap<String, String> = HashMap::from_iter(headers);
|
||||
|
||||
let mut headers = HeaderMap::new();
|
||||
for (h, v) in headers_raw {
|
||||
let name = HeaderName::from_str(&h)?;
|
||||
#[cfg(not(feature = "unsafe-headers"))]
|
||||
if is_unsafe_header(&name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
headers.append(name, HeaderValue::from_str(&v)?);
|
||||
}
|
||||
|
||||
match scheme {
|
||||
"http" | "https" => {
|
||||
@@ -228,38 +238,29 @@ pub async fn fetch<R: Runtime>(
|
||||
|
||||
let mut request = builder.build()?.request(method.clone(), url);
|
||||
|
||||
for (name, value) in &headers {
|
||||
let name = HeaderName::from_bytes(name.as_bytes())?;
|
||||
#[cfg(not(feature = "unsafe-headers"))]
|
||||
if is_unsafe_header(&name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
request = request.header(name, value);
|
||||
}
|
||||
|
||||
// POST and PUT requests should always have a 0 length content-length,
|
||||
// if there is no body. https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
|
||||
if data.is_none() && matches!(method, Method::POST | Method::PUT) {
|
||||
request = request.header(header::CONTENT_LENGTH, 0);
|
||||
headers.append(header::CONTENT_LENGTH, HeaderValue::from_str("0")?);
|
||||
}
|
||||
|
||||
if headers.contains_key(header::RANGE.as_str()) {
|
||||
if headers.contains_key(header::RANGE) {
|
||||
// https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 18
|
||||
// If httpRequest’s header list contains `Range`, then append (`Accept-Encoding`, `identity`)
|
||||
request = request.header(header::ACCEPT_ENCODING, "identity");
|
||||
headers.append(header::ACCEPT_ENCODING, HeaderValue::from_str("identity")?);
|
||||
}
|
||||
|
||||
if !headers.contains_key(header::USER_AGENT.as_str()) {
|
||||
request = request.header(header::USER_AGENT, HTTP_USER_AGENT);
|
||||
if !headers.contains_key(header::USER_AGENT) {
|
||||
headers.append(header::USER_AGENT, HeaderValue::from_str(HTTP_USER_AGENT)?);
|
||||
}
|
||||
|
||||
if cfg!(feature = "unsafe-headers")
|
||||
&& !headers.contains_key(header::ORIGIN.as_str())
|
||||
{
|
||||
// ensure we have an Origin header set
|
||||
if cfg!(not(feature = "unsafe-headers")) || !headers.contains_key(header::ORIGIN) {
|
||||
if let Ok(url) = webview.url() {
|
||||
request =
|
||||
request.header(header::ORIGIN, url.origin().ascii_serialization());
|
||||
headers.append(
|
||||
header::ORIGIN,
|
||||
HeaderValue::from_str(&url.origin().ascii_serialization())?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +268,8 @@ pub async fn fetch<R: Runtime>(
|
||||
request = request.body(data);
|
||||
}
|
||||
|
||||
request = request.headers(headers);
|
||||
|
||||
let fut = async move { request.send().await.map_err(Into::into) };
|
||||
let mut resources_table = webview.resources_table();
|
||||
let rid = resources_table.add_request(Box::pin(fut));
|
||||
|
||||
@@ -1 +1 @@
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_POSITIONER__=function(t){"use strict";async function e(t,e={},o){return window.__TAURI_INTERNALS__.invoke(t,e,o)}var o;return"function"==typeof SuppressedError&&SuppressedError,t.Position=void 0,(o=t.Position||(t.Position={}))[o.TopLeft=0]="TopLeft",o[o.TopRight=1]="TopRight",o[o.BottomLeft=2]="BottomLeft",o[o.BottomRight=3]="BottomRight",o[o.TopCenter=4]="TopCenter",o[o.BottomCenter=5]="BottomCenter",o[o.LeftCenter=6]="LeftCenter",o[o.RightCenter=7]="RightCenter",o[o.Center=8]="Center",o[o.TrayLeft=9]="TrayLeft",o[o.TrayBottomLeft=10]="TrayBottomLeft",o[o.TrayRight=11]="TrayRight",o[o.TrayBottomRight=12]="TrayBottomRight",o[o.TrayCenter=13]="TrayCenter",o[o.TrayBottomCenter=14]="TrayBottomCenter",t.handleIconState=async function(t){const o={};o[`${t.rect.size.type}`]={width:t.rect.size.width,height:t.rect.size.height};const i={};i[`${t.rect.position.type}`]={x:t.rect.position.x,y:t.rect.position.y},await e("plugin:positioner|set_tray_icon_state",{position:i,size:o})},t.moveWindow=async function(t){await e("plugin:positioner|move_window",{position:t})},t}({});Object.defineProperty(window.__TAURI__,"positioner",{value:__TAURI_PLUGIN_POSITIONER__})}
|
||||
if("__TAURI__"in window){var __TAURI_PLUGIN_POSITIONER__=function(t){"use strict";async function o(t,o={},e){return window.__TAURI_INTERNALS__.invoke(t,o,e)}var e;return"function"==typeof SuppressedError&&SuppressedError,t.Position=void 0,(e=t.Position||(t.Position={}))[e.TopLeft=0]="TopLeft",e[e.TopRight=1]="TopRight",e[e.BottomLeft=2]="BottomLeft",e[e.BottomRight=3]="BottomRight",e[e.TopCenter=4]="TopCenter",e[e.BottomCenter=5]="BottomCenter",e[e.LeftCenter=6]="LeftCenter",e[e.RightCenter=7]="RightCenter",e[e.Center=8]="Center",e[e.TrayLeft=9]="TrayLeft",e[e.TrayBottomLeft=10]="TrayBottomLeft",e[e.TrayRight=11]="TrayRight",e[e.TrayBottomRight=12]="TrayBottomRight",e[e.TrayCenter=13]="TrayCenter",e[e.TrayBottomCenter=14]="TrayBottomCenter",t.handleIconState=async function(t){await o("plugin:positioner|set_tray_icon_state",{position:t.rect.position,size:t.rect.size})},t.moveWindow=async function(t){await o("plugin:positioner|move_window",{position:t})},t}({});Object.defineProperty(window.__TAURI__,"positioner",{value:__TAURI_PLUGIN_POSITIONER__})}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
const COMMANDS: &[&str] = &["move_window"];
|
||||
const COMMANDS: &[&str] = &["move_window", "set_tray_icon_state"];
|
||||
|
||||
fn main() {
|
||||
tauri_plugin::Builder::new(COMMANDS)
|
||||
|
||||
@@ -40,20 +40,8 @@ export async function moveWindow(to: Position): Promise<void> {
|
||||
}
|
||||
|
||||
export async function handleIconState(event: TrayIconEvent): Promise<void> {
|
||||
const size = {} as Record<string, unknown>
|
||||
size[`${event.rect.size.type}`] = {
|
||||
width: event.rect.size.width,
|
||||
height: event.rect.size.height
|
||||
}
|
||||
|
||||
const position = {} as Record<string, unknown>
|
||||
position[`${event.rect.position.type}`] = {
|
||||
x: event.rect.position.x,
|
||||
y: event.rect.position.y
|
||||
}
|
||||
|
||||
await invoke('plugin:positioner|set_tray_icon_state', {
|
||||
position,
|
||||
size
|
||||
position: event.rect.position,
|
||||
size: event.rect.size
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,5 +4,10 @@
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-set-tray-icon-state"
|
||||
description = "Enables the set_tray_icon_state to handle events and set the TrayIcon state."
|
||||
description = "Enables the set_tray_icon_state command without any pre-configured scope."
|
||||
commands.allow = ["set_tray_icon_state"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-set-tray-icon-state"
|
||||
description = "Denies the set_tray_icon_state command without any pre-configured scope."
|
||||
commands.deny = ["set_tray_icon_state"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Default Permission
|
||||
|
||||
Allows the move_window command
|
||||
Allows the moveWindow and handleIconState APIs
|
||||
|
||||
- `allow-move-window`
|
||||
- `set-tray-icon-state`
|
||||
@@ -48,7 +48,20 @@ Denies the move_window command without any pre-configured scope.
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the set_tray_icon_state to handle events and set the TrayIcon state.
|
||||
Enables the set_tray_icon_state command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`positioner:deny-set-tray-icon-state`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the set_tray_icon_state command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"$schema" = "schemas/schema.json"
|
||||
[default]
|
||||
description = "Allows the move_window command"
|
||||
description = "Allows the moveWindow and handleIconState APIs"
|
||||
permissions = ["allow-move-window", "set-tray-icon-state"]
|
||||
|
||||
@@ -305,12 +305,17 @@
|
||||
"const": "deny-move-window"
|
||||
},
|
||||
{
|
||||
"description": "Enables the set_tray_icon_state to handle events and set the TrayIcon state.",
|
||||
"description": "Enables the set_tray_icon_state command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-set-tray-icon-state"
|
||||
},
|
||||
{
|
||||
"description": "Allows the move_window command",
|
||||
"description": "Denies the set_tray_icon_state command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-set-tray-icon-state"
|
||||
},
|
||||
{
|
||||
"description": "Allows the moveWindow and handleIconState APIs",
|
||||
"type": "string",
|
||||
"const": "default"
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ pub fn kill<R: Runtime>(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open<R: Runtime>(
|
||||
pub async fn open<R: Runtime>(
|
||||
_window: Window<R>,
|
||||
shell: State<'_, Shell<R>>,
|
||||
path: String,
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.0.0"
|
||||
"@tauri-apps/cli": "2.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.0.0",
|
||||
"@tauri-apps/cli": "2.0.2",
|
||||
"vite": "^5.0.12",
|
||||
"typescript": "^5.4.7"
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "2.0.0",
|
||||
"@tauri-apps/cli": "2.0.2",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.4.7"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user