diff --git a/.changes/dialog-return-path.md b/.changes/dialog-return-path.md
new file mode 100644
index 00000000..2bd7b4db
--- /dev/null
+++ b/.changes/dialog-return-path.md
@@ -0,0 +1,7 @@
+---
+"dialog": patch
+"dialog-js": patch
+---
+
+The `open` function now returns a string representing either the file path or URI instead of an object.
+To read the file data, use the `fs` APIs.
diff --git a/.changes/resolve-content-uris.md b/.changes/resolve-content-uris.md
new file mode 100644
index 00000000..781eff70
--- /dev/null
+++ b/.changes/resolve-content-uris.md
@@ -0,0 +1,5 @@
+---
+"fs": patch:feat
+---
+
+Resolve `content://` path URIs on Android.
diff --git a/Cargo.lock b/Cargo.lock
index 302518d1..c685b090 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6359,9 +6359,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79776954e2cd6b6c3b56e2cd99905a3a166017495a39ac8eb4c85dd8ea8704b4"
+checksum = "7d386b956b09cf88301912453829269f3914b3c813020d429ed8110c75e9dded"
dependencies = [
"anyhow",
"bytes",
@@ -6412,9 +6412,9 @@ dependencies = [
[[package]]
name = "tauri-build"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fc103bde77870e08d5fc8765615b9615997827550b626fbc4ebbd7a1fbfe2a2"
+checksum = "1e79aafbbfc8262d7937675cb44c397e975ab8e0cd722db1c37de694fd443570"
dependencies = [
"anyhow",
"cargo_toml",
@@ -6436,9 +6436,9 @@ dependencies = [
[[package]]
name = "tauri-codegen"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea061e6be9b37ab455eadc189f45617deafc85c94f78f9cd584862a6deaa83d1"
+checksum = "5ce4e521130c5d7b377ddfdc43310ece626b67ec07ae74174407ad7e6cd17d20"
dependencies = [
"base64 0.22.1",
"brotli",
@@ -6463,9 +6463,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e20d6f6f96f55a43339c465b3c8205d71940372d54d7c665c5329e8e4ba35d0"
+checksum = "a5995206394cd30411fc5c8ae195e498357f63e11ed960ea32b53512dcb2a5a5"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -6477,9 +6477,9 @@ dependencies = [
[[package]]
name = "tauri-plugin"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec01af01098a286d3e430c1fa947bfd77bc8011ecb209438af4444b02d82b29e"
+checksum = "0ebbdbf4e6d7328e0c0f2427b4f56d792ee1ae84ab4fb0286b81a2e408836046"
dependencies = [
"anyhow",
"glob",
@@ -6612,6 +6612,7 @@ dependencies = [
"tauri-plugin",
"tauri-plugin-fs",
"thiserror",
+ "url",
]
[[package]]
@@ -6971,9 +6972,9 @@ dependencies = [
[[package]]
name = "tauri-runtime"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4e736d3293f8347e5d2c5b250fe0e5b873499f5483578b139445dbbf802e2e5"
+checksum = "6e49398fb1d7736e41099aa7efaf45d599e480a36b3e7f88977b547b662d7253"
dependencies = [
"dpi",
"gtk",
@@ -6990,9 +6991,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fead81c1bd0205d5f02580e64f522704618274e784c2d1c127e4ba19acd0b79"
+checksum = "8b2ce1dca90243bd4a77a1020847688590e1ded2f6d190d5a96877b0039f0500"
dependencies = [
"cocoa 0.26.0",
"gtk",
@@ -7014,9 +7015,9 @@ dependencies = [
[[package]]
name = "tauri-utils"
-version = "2.0.0-rc.3"
+version = "2.0.0-rc.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "285af18e09665ea15fdda04cb28fb579a4d71b4e1640628489fecca98838ca9a"
+checksum = "2d702b62eed4cf89034926cb1834e2d13a7d745ea08a457fd336f94cde48f2fb"
dependencies = [
"aes-gcm",
"brotli",
diff --git a/Cargo.toml b/Cargo.toml
index e24823f7..5ba3f825 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,10 +11,10 @@ resolver = "2"
[workspace.dependencies]
serde = { version = "1", features = ["derive"] }
log = "0.4"
-tauri = { version = "2.0.0-rc.3", default-features = false }
-tauri-build = "2.0.0-rc.3"
-tauri-plugin = "2.0.0-rc.3"
-tauri-utils = "2.0.0-rc.3"
+tauri = { version = "2.0.0-rc.5", default-features = false }
+tauri-build = "2.0.0-rc.5"
+tauri-plugin = "2.0.0-rc.5"
+tauri-utils = "2.0.0-rc.5"
serde_json = "1"
thiserror = "1"
url = "2"
diff --git a/examples/api/package.json b/examples/api/package.json
index 6c4d1d4a..8d28c501 100644
--- a/examples/api/package.json
+++ b/examples/api/package.json
@@ -30,7 +30,7 @@
"@iconify-json/codicon": "^1.1.37",
"@iconify-json/ph": "^1.1.8",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
- "@tauri-apps/cli": "2.0.0-rc.4",
+ "@tauri-apps/cli": "2.0.0-rc.6",
"@unocss/extractor-svelte": "^0.62.0",
"svelte": "^4.2.8",
"unocss": "^0.62.0",
diff --git a/examples/api/src-tauri/capabilities/base.json b/examples/api/src-tauri/capabilities/base.json
index da21da28..1a030079 100644
--- a/examples/api/src-tauri/capabilities/base.json
+++ b/examples/api/src-tauri/capabilities/base.json
@@ -61,6 +61,9 @@
"clipboard-manager:allow-write-text",
"clipboard-manager:allow-read-image",
"clipboard-manager:allow-write-image",
+ "fs:allow-open",
+ "fs:allow-write",
+ "fs:allow-read",
"fs:allow-rename",
"fs:allow-mkdir",
"fs:allow-remove",
diff --git a/examples/api/src-tauri/gen/android/.idea/gradle.xml b/examples/api/src-tauri/gen/android/.idea/gradle.xml
index 83b872db..120d2e91 100644
--- a/examples/api/src-tauri/gen/android/.idea/gradle.xml
+++ b/examples/api/src-tauri/gen/android/.idea/gradle.xml
@@ -27,6 +27,7 @@
+
diff --git a/examples/api/src/views/Dialog.svelte b/examples/api/src/views/Dialog.svelte
index 3e594c90..462eecff 100644
--- a/examples/api/src/views/Dialog.svelte
+++ b/examples/api/src/views/Dialog.svelte
@@ -23,11 +23,7 @@
async function prompt() {
confirm("Do you want to do something?")
- .then((res) =>
- onMessage(
- res ? "Yes" : "No"
- )
- )
+ .then((res) => onMessage(res ? "Yes" : "No"))
.catch(onMessage);
}
@@ -67,14 +63,15 @@
if (Array.isArray(res)) {
onMessage(res);
} else {
- var pathToRead = typeof res === "string" ? res : res.path;
+ var pathToRead = res;
var isFile = pathToRead.match(/\S+\.\S+$/g);
readFile(pathToRead)
.then(function (response) {
if (isFile) {
if (
pathToRead.includes(".png") ||
- pathToRead.includes(".jpg")
+ pathToRead.includes(".jpg") ||
+ pathToRead.includes(".jpeg")
) {
arrayBufferToBase64(
new Uint8Array(response),
@@ -144,5 +141,7 @@
>Open save dialog
-
+
diff --git a/plugins/deep-link/examples/app/package.json b/plugins/deep-link/examples/app/package.json
index 81959ae5..5fac24a2 100644
--- a/plugins/deep-link/examples/app/package.json
+++ b/plugins/deep-link/examples/app/package.json
@@ -14,7 +14,7 @@
"@tauri-apps/plugin-deep-link": "2.0.0-rc.0"
},
"devDependencies": {
- "@tauri-apps/cli": "2.0.0-rc.4",
+ "@tauri-apps/cli": "2.0.0-rc.6",
"typescript": "^5.2.2",
"vite": "^5.0.13"
}
diff --git a/plugins/dialog/Cargo.toml b/plugins/dialog/Cargo.toml
index 91f1df1b..3064dc8d 100644
--- a/plugins/dialog/Cargo.toml
+++ b/plugins/dialog/Cargo.toml
@@ -17,6 +17,9 @@ targets = ["x86_64-unknown-linux-gnu", "x86_64-linux-android"]
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
+[dev-dependencies]
+tauri = { workspace = true, features = [ "wry" ] }
+
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
@@ -24,6 +27,7 @@ tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
dunce = { workspace = true }
+url = { workspace = true }
tauri-plugin-fs = { path = "../fs", version = "2.0.0-rc.0" }
[target.'cfg(target_os = "ios")'.dependencies]
diff --git a/plugins/dialog/android/src/main/java/DialogPlugin.kt b/plugins/dialog/android/src/main/java/DialogPlugin.kt
index fe0e227e..15af6808 100644
--- a/plugins/dialog/android/src/main/java/DialogPlugin.kt
+++ b/plugins/dialog/android/src/main/java/DialogPlugin.kt
@@ -30,7 +30,6 @@ class Filter {
class FilePickerOptions {
lateinit var filters: Array
var multiple: Boolean? = null
- var readData: Boolean? = null
}
@InvokeArg
@@ -95,7 +94,7 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
try {
when (result.resultCode) {
Activity.RESULT_OK -> {
- val callResult = createPickFilesResult(result.data, filePickerOptions?.readData ?: false)
+ val callResult = createPickFilesResult(result.data)
invoke.resolve(callResult)
}
Activity.RESULT_CANCELED -> invoke.reject("File picker cancelled")
@@ -108,49 +107,23 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
}
}
- private fun createPickFilesResult(data: Intent?, readData: Boolean): JSObject {
+ private fun createPickFilesResult(data: Intent?): JSObject {
val callResult = JSObject()
- val filesResultList: MutableList = ArrayList()
if (data == null) {
- callResult.put("files", JSArray.from(filesResultList))
+ callResult.put("files", null)
return callResult
}
- val uris: MutableList = ArrayList()
+ val uris: MutableList = ArrayList()
if (data.clipData == null) {
val uri: Uri? = data.data
- uris.add(uri)
+ uris.add(uri?.toString())
} else {
for (i in 0 until data.clipData!!.itemCount) {
val uri: Uri = data.clipData!!.getItemAt(i).uri
- uris.add(uri)
+ uris.add(uri.toString())
}
}
- for (i in uris.indices) {
- val uri = uris[i] ?: continue
- val fileResult = JSObject()
- if (readData) {
- fileResult.put("base64Data", FilePickerUtils.getDataFromUri(activity, uri))
- }
- val duration = FilePickerUtils.getDurationFromUri(activity, uri)
- if (duration != null) {
- fileResult.put("duration", duration)
- }
- val resolution = FilePickerUtils.getHeightAndWidthFromUri(activity, uri)
- if (resolution != null) {
- fileResult.put("height", resolution.height)
- fileResult.put("width", resolution.width)
- }
- fileResult.put("mimeType", FilePickerUtils.getMimeTypeFromUri(activity, uri))
- val modifiedAt = FilePickerUtils.getModifiedAtFromUri(activity, uri)
- if (modifiedAt != null) {
- fileResult.put("modifiedAt", modifiedAt)
- }
- fileResult.put("name", FilePickerUtils.getNameFromUri(activity, uri))
- fileResult.put("path", FilePickerUtils.getPathFromUri(activity, uri))
- fileResult.put("size", FilePickerUtils.getSizeFromUri(activity, uri))
- filesResultList.add(fileResult)
- }
- callResult.put("files", JSArray.from(filesResultList.toTypedArray()))
+ callResult.put("files", JSArray.from(uris.toTypedArray()))
return callResult
}
diff --git a/plugins/dialog/guest-js/index.ts b/plugins/dialog/guest-js/index.ts
index 7d1fa99d..9624718d 100644
--- a/plugins/dialog/guest-js/index.ts
+++ b/plugins/dialog/guest-js/index.ts
@@ -4,18 +4,6 @@
import { invoke } from "@tauri-apps/api/core";
-interface FileResponse {
- base64Data?: string;
- duration?: number;
- height?: number;
- width?: number;
- mimeType?: string;
- modifiedAt?: number;
- name?: string;
- path: string;
- size: number;
-}
-
/**
* Extension filters for the file dialog.
*
@@ -117,8 +105,8 @@ type OpenDialogReturn = T["directory"] extends true
? string[] | null
: string | null
: T["multiple"] extends true
- ? FileResponse[] | null
- : FileResponse | null;
+ ? string[] | null
+ : string | null;
/**
* Open a file/directory selection dialog.
@@ -306,7 +294,6 @@ async function confirm(
export type {
DialogFilter,
- FileResponse,
OpenDialogOptions,
OpenDialogReturn,
SaveDialogOptions,
diff --git a/plugins/dialog/ios/Sources/DialogPlugin.swift b/plugins/dialog/ios/Sources/DialogPlugin.swift
index 26c9fefa..cb8f19e4 100644
--- a/plugins/dialog/ios/Sources/DialogPlugin.swift
+++ b/plugins/dialog/ios/Sources/DialogPlugin.swift
@@ -29,7 +29,6 @@ struct Filter: Decodable {
struct FilePickerOptions: Decodable {
var multiple: Bool?
- var readData: Bool?
var filters: [Filter]?
}
@@ -136,55 +135,9 @@ class DialogPlugin: Plugin {
public func onFilePickerEvent(_ event: FilePickerEvent) {
switch event {
case .selected(let urls):
- let readData = pendingInvokeArgs?.readData ?? false
- do {
- let filesResult = try urls.map { (url: URL) -> JSObject in
- var file = JSObject()
-
- let mimeType = filePickerController.getMimeTypeFromUrl(url)
- let isVideo = mimeType.hasPrefix("video")
- let isImage = mimeType.hasPrefix("image")
-
- if readData {
- file["data"] = try Data(contentsOf: url).base64EncodedString()
- }
-
- if isVideo {
- file["duration"] = filePickerController.getVideoDuration(url)
- let (height, width) = filePickerController.getVideoDimensions(url)
- if let height = height {
- file["height"] = height
- }
- if let width = width {
- file["width"] = width
- }
- } else if isImage {
- let (height, width) = filePickerController.getImageDimensions(url)
- if let height = height {
- file["height"] = height
- }
- if let width = width {
- file["width"] = width
- }
- }
-
- file["modifiedAt"] = filePickerController.getModifiedAtFromUrl(url)
- file["mimeType"] = mimeType
- file["name"] = url.lastPathComponent
- file["path"] = url.absoluteString
- file["size"] = try filePickerController.getSizeFromUrl(url)
- return file
- }
- pendingInvoke?.resolve(["files": filesResult])
- } catch let error as NSError {
- pendingInvoke?.reject(error.localizedDescription, error: error)
- return
- }
-
pendingInvoke?.resolve(["files": urls])
case .cancelled:
- let files: JSArray = []
- pendingInvoke?.resolve(["files": files])
+ pendingInvoke?.resolve(["files": nil])
case .error(let error):
pendingInvoke?.reject(error)
}
diff --git a/plugins/dialog/src/commands.rs b/plugins/dialog/src/commands.rs
index 7e50d591..25716e91 100644
--- a/plugins/dialog/src/commands.rs
+++ b/plugins/dialog/src/commands.rs
@@ -8,17 +8,17 @@ use serde::{Deserialize, Serialize};
use tauri::{command, Manager, Runtime, State, Window};
use tauri_plugin_fs::FsExt;
-use crate::{Dialog, FileDialogBuilder, FileResponse, MessageDialogKind, Result};
+use crate::{Dialog, FileDialogBuilder, FilePath, MessageDialogKind, Result};
#[derive(Serialize)]
#[serde(untagged)]
pub enum OpenResponse {
#[cfg(desktop)]
- Folders(Option>),
+ Folders(Option>),
#[cfg(desktop)]
- Folder(Option),
- Files(Option>),
- File(Option),
+ Folder(Option),
+ Files(Option>),
+ File(Option),
}
#[allow(dead_code)]
@@ -136,25 +136,26 @@ pub(crate) async fn open(
let folders = dialog_builder.blocking_pick_folders();
if let Some(folders) = &folders {
for folder in folders {
- if let Some(s) = window.try_fs_scope() {
- s.allow_directory(folder, options.recursive);
+ if let Ok(path) = folder.path() {
+ if let Some(s) = window.try_fs_scope() {
+ s.allow_directory(path, options.recursive);
+ }
}
}
}
- OpenResponse::Folders(folders.map(|folders| {
- folders
- .iter()
- .map(|p| dunce::simplified(p).to_path_buf())
- .collect()
- }))
+ OpenResponse::Folders(
+ folders.map(|folders| folders.into_iter().map(|p| p.simplified()).collect()),
+ )
} else {
let folder = dialog_builder.blocking_pick_folder();
- if let Some(path) = &folder {
- if let Some(s) = window.try_fs_scope() {
- s.allow_directory(path, options.recursive);
+ if let Some(folder) = &folder {
+ if let Ok(path) = folder.path() {
+ if let Some(s) = window.try_fs_scope() {
+ s.allow_directory(path, options.recursive);
+ }
}
}
- OpenResponse::Folder(folder.map(|p| dunce::simplified(&p).to_path_buf()))
+ OpenResponse::Folder(folder.map(|p| p.simplified()))
}
}
#[cfg(mobile)]
@@ -163,37 +164,28 @@ pub(crate) async fn open(
let files = dialog_builder.blocking_pick_files();
if let Some(files) = &files {
for file in files {
- if let Some(s) = window.try_fs_scope() {
- s.allow_file(&file.path);
+ if let Ok(path) = file.path() {
+ if let Some(s) = window.try_fs_scope() {
+ s.allow_file(&path);
+ }
+
+ window.state::().allow_file(&path)?;
}
- window
- .state::()
- .allow_file(&file.path)?;
}
}
- OpenResponse::Files(files.map(|files| {
- files
- .into_iter()
- .map(|mut f| {
- f.path = dunce::simplified(&f.path).to_path_buf();
- f
- })
- .collect()
- }))
+ OpenResponse::Files(files.map(|files| files.into_iter().map(|f| f.simplified()).collect()))
} else {
let file = dialog_builder.blocking_pick_file();
+
if let Some(file) = &file {
- if let Some(s) = window.try_fs_scope() {
- s.allow_file(&file.path);
+ if let Ok(path) = file.path() {
+ if let Some(s) = window.try_fs_scope() {
+ s.allow_file(&path);
+ }
+ window.state::().allow_file(&path)?;
}
- window
- .state::()
- .allow_file(&file.path)?;
}
- OpenResponse::File(file.map(|mut f| {
- f.path = dunce::simplified(&f.path).to_path_buf();
- f
- }))
+ OpenResponse::File(file.map(|f| f.simplified()))
};
Ok(res)
}
@@ -204,7 +196,7 @@ pub(crate) async fn save(
window: Window,
dialog: State<'_, Dialog>,
options: SaveDialogOptions,
-) -> Result