mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-10 14:13:55 +02:00
* feat(dialog) - Support fileAccessMode for open dialog (#3030) On iOS, when trying to access a file that exists outside of the app sandbox, one of 2 things need to happen to be able to perform any operations on said file: * A copy of the file needs to be made to the internal app sandbox * The method startAccessingSecurityScopedResource needs to be called. Previously, a copy of the file was always being made when a file was selected through the picker dialog. While this did ensure there were no file access exceptions when reading from the file, it does not scale well for large files. To resolve this, we now support `fileAccessMode`, which allows a file handle to be returned without copying the file to the app sandbox. This MR only supports this change for iOS; MacOS has a different set of needs for security scoped resources. See discussion in #3716 for more discussion of the difference between iOS and MacOS. See MR #3185 to see how these scoped files will be accessible using security scoping. * fmt, clippy * use enum --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
@@ -9,8 +9,9 @@ use tauri::{command, Manager, Runtime, State, Window};
|
||||
use tauri_plugin_fs::FsExt;
|
||||
|
||||
use crate::{
|
||||
Dialog, FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogButtons,
|
||||
MessageDialogKind, MessageDialogResult, PickerMode, Result, CANCEL, NO, OK, YES,
|
||||
Dialog, FileAccessMode, FileDialogBuilder, FilePath, MessageDialogBuilder,
|
||||
MessageDialogButtons, MessageDialogKind, MessageDialogResult, PickerMode, Result, CANCEL, NO,
|
||||
OK, YES,
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -63,6 +64,10 @@ pub struct OpenDialogOptions {
|
||||
#[serde(default)]
|
||||
#[cfg_attr(mobile, allow(dead_code))]
|
||||
picker_mode: Option<PickerMode>,
|
||||
/// The file access mode of the dialog.
|
||||
#[serde(default)]
|
||||
#[cfg_attr(mobile, allow(dead_code))]
|
||||
file_access_mode: Option<FileAccessMode>,
|
||||
}
|
||||
|
||||
/// The options for the save dialog API.
|
||||
@@ -141,6 +146,9 @@ pub(crate) async fn open<R: Runtime>(
|
||||
let extensions: Vec<&str> = filter.extensions.iter().map(|s| &**s).collect();
|
||||
dialog_builder = dialog_builder.add_filter(filter.name, &extensions);
|
||||
}
|
||||
if let Some(file_access_mode) = options.file_access_mode {
|
||||
dialog_builder = dialog_builder.set_file_access_mode(file_access_mode);
|
||||
}
|
||||
|
||||
let res = if options.directory {
|
||||
#[cfg(desktop)]
|
||||
|
||||
@@ -53,6 +53,13 @@ pub enum PickerMode {
|
||||
Video,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum FileAccessMode {
|
||||
Copy,
|
||||
Scoped,
|
||||
}
|
||||
|
||||
pub(crate) const OK: &str = "Ok";
|
||||
pub(crate) const CANCEL: &str = "Cancel";
|
||||
pub(crate) const YES: &str = "Yes";
|
||||
@@ -191,7 +198,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
commands::save,
|
||||
commands::message,
|
||||
commands::ask,
|
||||
commands::confirm
|
||||
commands::confirm,
|
||||
])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
@@ -379,6 +386,7 @@ pub struct FileDialogBuilder<R: Runtime> {
|
||||
pub(crate) title: Option<String>,
|
||||
pub(crate) can_create_directories: Option<bool>,
|
||||
pub(crate) picker_mode: Option<PickerMode>,
|
||||
pub(crate) file_access_mode: Option<FileAccessMode>,
|
||||
#[cfg(desktop)]
|
||||
pub(crate) parent: Option<crate::desktop::WindowHandle>,
|
||||
}
|
||||
@@ -391,6 +399,7 @@ pub(crate) struct FileDialogPayload<'a> {
|
||||
filters: &'a Vec<Filter>,
|
||||
multiple: bool,
|
||||
picker_mode: &'a Option<PickerMode>,
|
||||
file_access_mode: &'a Option<FileAccessMode>,
|
||||
}
|
||||
|
||||
// raw window handle :(
|
||||
@@ -407,6 +416,7 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
title: None,
|
||||
can_create_directories: None,
|
||||
picker_mode: None,
|
||||
file_access_mode: None,
|
||||
#[cfg(desktop)]
|
||||
parent: None,
|
||||
}
|
||||
@@ -419,6 +429,7 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
filters: &self.filters,
|
||||
multiple,
|
||||
picker_mode: &self.picker_mode,
|
||||
file_access_mode: &self.file_access_mode,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +499,14 @@ impl<R: Runtime> FileDialogBuilder<R> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the file access mode of the dialog.
|
||||
/// This is only used on iOS.
|
||||
/// On desktop and Android, this option is ignored.
|
||||
pub fn set_file_access_mode(mut self, mode: FileAccessMode) -> Self {
|
||||
self.file_access_mode.replace(mode);
|
||||
self
|
||||
}
|
||||
|
||||
/// Shows the dialog to select a single file.
|
||||
///
|
||||
/// This is not a blocking operation,
|
||||
|
||||
Reference in New Issue
Block a user