tauri_plugin_android_fs/
models.rs

1use serde::{Deserialize, Serialize};
2
3/// Path to represent a file or directory.
4/// 
5/// # Note
6/// For compatibility, an interconversion to [`tauri_plugin_fs::FilePath`] is implemented, such as follwing.  
7/// This is lossy and also not guaranteed to work properly with other plugins.  
8/// However, reading and writing files by official [`tauri_plugin_fs`] etc. should work well.  
9/// ```no_run
10/// use tauri_plugin_android_fs::FileUri;
11/// use tauri_plugin_fs::FilePath;
12/// 
13/// let uri: FileUri = unimplemented!();
14/// let path: FilePath = uri.into();
15/// let uri: FileUri = path.into();
16/// ```
17/// 
18/// # Typescript type
19/// ```typescript
20/// type FileUri = {
21///     uri: string, // This can use as path for official tauri_plugin_fs
22///     documentTopTreeUri: string | null
23/// }
24/// ```
25#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
26#[serde(rename_all = "camelCase")]
27pub struct FileUri {
28    /// `file://` or `content://` URI of file or directory.
29    pub uri: String,
30
31    /// Only files/directories under the directory obtained by AndroidFs::show_manage_dir_dialog will own this.
32    pub document_top_tree_uri: Option<String>,
33}
34
35impl FileUri {
36
37    pub fn to_string(&self) -> crate::Result<String> {
38        serde_json::to_string(self).map_err(Into::into)
39    }
40
41    pub fn from_str(s: &str) -> crate::Result<Self> {
42        serde_json::from_str(s).map_err(Into::into)
43    }
44}
45
46impl From<&std::path::PathBuf> for FileUri {
47
48    fn from(value: &std::path::PathBuf) -> Self {
49        Self { uri: format!("file://{}", value.to_string_lossy()), document_top_tree_uri: None }
50    }
51}
52
53impl From<std::path::PathBuf> for FileUri {
54
55    fn from(ref value: std::path::PathBuf) -> Self {
56        value.into()
57    }
58}
59
60impl From<tauri_plugin_fs::FilePath> for FileUri {
61
62    fn from(value: tauri_plugin_fs::FilePath) -> Self {
63        match value {
64            tauri_plugin_fs::FilePath::Url(url) => Self { uri: url.to_string(), document_top_tree_uri: None },
65            tauri_plugin_fs::FilePath::Path(path_buf) => path_buf.into(),
66        }
67    }
68}
69
70impl From<FileUri> for tauri_plugin_fs::FilePath {
71
72    fn from(value: FileUri) -> Self {
73        let result: std::result::Result<_, std::convert::Infallible> = value.uri.parse();
74
75        // This will not cause panic. 
76        // Because result err is infallible.
77        result.unwrap()
78    }
79}
80
81#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
82#[serde(rename_all = "camelCase")]
83pub enum Entry {
84
85    #[non_exhaustive]
86    File {
87        uri: FileUri,
88        name: String,
89        last_modified: std::time::SystemTime,
90        len: u64,
91        mime_type: String,
92    },
93
94    #[non_exhaustive]
95    Dir {
96        uri: FileUri,
97        name: String,
98        last_modified: std::time::SystemTime,
99    }
100}
101
102/// Access mode
103#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
104pub enum PersistableAccessMode {
105
106    /// Read access.
107    Read,
108
109    /// Write access.
110    Write,
111
112    /// Read-write access.
113    ReadAndWrite,
114}
115
116#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
117pub enum PersistedUriPermission {
118    File {
119        uri: FileUri,
120        can_read: bool,
121        can_write: bool,
122    },
123    Dir {
124        uri: FileUri,
125        can_read: bool,
126        can_write: bool,
127    }
128}
129
130impl PersistedUriPermission {
131
132    pub fn uri(&self) -> &FileUri {
133        match self {
134            PersistedUriPermission::File { uri, .. } => uri,
135            PersistedUriPermission::Dir { uri, .. } => uri,
136        }
137    }
138
139    pub fn can_read(&self) -> bool {
140        match self {
141            PersistedUriPermission::File { can_read, .. } => *can_read,
142            PersistedUriPermission::Dir { can_read, .. } => *can_read,
143        }
144    }
145
146    pub fn can_write(&self) -> bool {
147        match self {
148            PersistedUriPermission::File { can_write, .. } => *can_write,
149            PersistedUriPermission::Dir { can_write, .. } => *can_write,
150        }
151    }
152
153    pub fn is_file(&self) -> bool {
154        matches!(self, PersistedUriPermission::File { .. })
155    }
156
157    pub fn is_dir(&self) -> bool {
158        matches!(self, PersistedUriPermission::Dir { .. })
159    }
160}
161
162#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
163pub struct Size {
164    pub width: u32,
165    pub height: u32
166}
167
168#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
169#[non_exhaustive]
170pub enum ImageFormat {
171
172    /// - Loss less
173    /// - Support transparency
174    Png,
175
176    /// - Lossy
177    /// - Unsupport transparency
178    Jpeg,
179
180    /// - Lossy (**Not loss less**)
181    /// - Support transparency
182    Webp,
183
184    /// - Lossy
185    /// - Unsupport transparency
186    JpegWith {
187
188        /// Range is `0.0 ~ 1.0`  
189        /// 0.0 means compress for the smallest size.  
190        /// 1.0 means compress for max visual quality.  
191        quality: f32
192    },
193
194    /// - Lossy
195    /// - Support transparency
196    WebpWith {
197        
198        /// Range is `0.0 ~ 1.0`  
199        /// 0.0 means compress for the smallest size.  
200        /// 1.0 means compress for max visual quality.  
201        quality: f32
202    }
203}
204
205/// Access mode
206#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
207#[non_exhaustive]
208pub enum FileAccessMode {
209
210    /// Opens the file in read-only mode.
211    /// 
212    /// FileDescriptor mode: "r"
213    Read,
214
215    /// Opens the file in write-only mode.  
216    /// **This may or may not truncate existing contents.**  
217    /// So please use [`FileAccessMode::WriteTruncate`] or [`FileAccessMode::WriteAppend`] instead.  
218    ///
219    /// FileDescriptor mode: "w"
220    #[deprecated(note = "This may or may not truncate existing contents. So please use WriteTruncate or WriteAppend instead.")]
221    Write,
222
223    /// Opens the file in write-only mode.
224    /// The existing content is truncated (deleted), and new data is written from the beginning.
225    /// Creates a new file if it does not exist.
226    ///
227    /// FileDescriptor mode: "wt"
228    WriteTruncate,
229
230    /// Opens the file in write-only mode.
231    /// The existing content is preserved, and new data is appended to the end of the file.
232    /// Creates a new file if it does not exist.
233    /// 
234    /// FileDescriptor mode: "wa"
235    WriteAppend,
236
237    /// Opens the file in read-write mode.  
238    /// 
239    /// FileDescriptor mode: "rw"
240    ReadWrite,
241
242    /// Opens the file in read-write mode.
243    /// The existing content is truncated (deleted), and new data is written from the beginning.
244    /// Creates a new file if it does not exist.
245    ///
246    /// FileDescriptor mode: "rwt"
247    ReadWriteTruncate,
248}
249
250/// Filters for VisualMediaPicker.
251#[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)]
252#[non_exhaustive]
253pub enum VisualMediaTarget {
254
255    /// Allow only images to be selected.  
256    ImageOnly,
257
258    /// Allow only videos to be selected.  
259    VideoOnly,
260
261    /// Allow only images and videos to be selected.  
262    ImageAndVideo,
263}
264
265/// The application specific directory.  
266#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
267#[non_exhaustive]
268pub enum PrivateDir {
269
270    /// The application specific persistent-data directory.  
271    /// 
272    /// The system prevents other apps and user from accessing these locations. 
273    /// In cases where the device is rooted or the user has special permissions, the user may be able to access this.   
274    ///  
275    /// These files will be deleted when the app is uninstalled and may also be deleted at the user’s request.  
276    /// 
277    /// ex: `/data/user/0/{app-package-name}/files`
278    Data,
279
280    /// The application specific cache directory.  
281    /// 
282    /// The system prevents other apps and user from accessing these locations. 
283    /// In cases where the device is rooted or the user has special permissions, the user may be able to access this.   
284    /// 
285    /// These files will be deleted when the app is uninstalled and may also be deleted at the user’s request. 
286    /// In addition, the system will automatically delete files in this directory as disk space is needed elsewhere on the device.  
287    /// 
288    /// ex: `/data/user/0/{app-package-name}/cache`
289    Cache,
290}
291
292#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
293#[non_exhaustive]
294pub enum PublicDir {
295    
296    #[serde(untagged)]
297    Image(PublicImageDir),
298
299    #[serde(untagged)]
300    Video(PublicVideoDir),
301
302    #[serde(untagged)]
303    Audio(PublicAudioDir),
304
305    #[serde(untagged)]
306    GeneralPurpose(PublicGeneralPurposeDir),
307}
308
309/// Directory in which to place images that are available to other applications and users.  
310#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
311#[non_exhaustive]
312pub enum PublicImageDir {
313
314    /// Standard directory in which to place pictures that are available to the user.  
315    /// 
316    /// ex: `~/Pictures`
317    Pictures,
318
319    /// The traditional location for pictures and videos when mounting the device as a camera.  
320    /// 
321    /// ex: `~/DCIM`
322    DCIM,
323}
324
325/// Directory in which to place videos that are available to other applications and users.  
326#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
327#[non_exhaustive]
328pub enum PublicVideoDir {
329
330	/// Standard directory in which to place movies that are available to the user.  
331	/// 
332	/// ex: `~/Movies`
333	Movies,
334
335	/// The traditional location for pictures and videos when mounting the device as a camera.  
336	/// 
337	/// ex: `~/DCIM`
338	DCIM,
339}
340
341/// Directory in which to place audios that are available to other applications and users.  
342#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
343#[non_exhaustive]
344pub enum PublicAudioDir {
345
346    /// Standard directory in which to place movies that are available to the user.  
347    /// 
348    /// ex: `~/Music`
349    Music,
350
351    /// Standard directory in which to place any audio files that should be in the list of alarms that the user can select (not as regular music).  
352    /// 
353    /// ex: `~/Alarms`
354    Alarms,
355
356    /// Standard directory in which to place any audio files that should be in the list of audiobooks that the user can select (not as regular music).  
357    /// 
358    /// This is not available on Android 9 (API level 28) and lower.  
359    /// 
360    /// ex: `~/Audiobooks`  
361    Audiobooks,
362
363    /// Standard directory in which to place any audio files that should be in the list of notifications that the user can select (not as regular music).  
364    /// 
365    /// ex: `~/Notifications`
366    Notifications,
367
368    /// Standard directory in which to place any audio files that should be in the list of podcasts that the user can select (not as regular music).  
369    /// 
370    /// ex: `~/Podcasts`
371    Podcasts,
372
373    /// Standard directory in which to place any audio files that should be in the list of ringtones that the user can select (not as regular music).  
374    /// 
375    /// ex: `~/Ringtones`
376    Ringtones,
377
378    /// Standard directory in which to place any audio files that should be in the list of voice recordings recorded by voice recorder apps that the user can select (not as regular music).   
379    /// 
380    /// This is not available on Android 11 (API level 30) and lower.  
381    /// 
382    /// ex: `~/Recordings`
383    Recordings,
384}
385
386/// Directory in which to place files that are available to other applications and users.  
387#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
388#[non_exhaustive]
389pub enum PublicGeneralPurposeDir {
390
391    /// Standard directory in which to place documents that have been created by the user.  
392    /// 
393    /// ex: `~/Documents`
394    Documents,
395
396    /// Standard directory in which to place files that have been downloaded by the user.  
397    /// 
398    /// ex: `~/Download`  
399    Download,
400}
401
402impl std::fmt::Display for PublicImageDir {
403    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
404        match self {
405            PublicImageDir::Pictures => write!(f, "Pictures"),
406            PublicImageDir::DCIM => write!(f, "DCIM"),
407        }
408    }
409}
410
411impl std::fmt::Display for PublicVideoDir {
412    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
413        match self {
414            PublicVideoDir::Movies => write!(f, "Movies"),
415            PublicVideoDir::DCIM => write!(f, "DCIM"),
416        }
417    }
418}
419
420impl std::fmt::Display for PublicAudioDir {
421    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422        match self {
423            PublicAudioDir::Music => write!(f, "Music"),
424            PublicAudioDir::Alarms => write!(f, "Alarms"),
425            PublicAudioDir::Audiobooks => write!(f, "Audiobooks"),
426            PublicAudioDir::Notifications => write!(f, "Notifications"),
427            PublicAudioDir::Podcasts => write!(f, "Podcasts"),
428            PublicAudioDir::Ringtones => write!(f, "Ringtones"),
429            PublicAudioDir::Recordings => write!(f, "Recordings"),
430        }
431    }
432}
433
434impl std::fmt::Display for PublicGeneralPurposeDir {
435    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
436        match self {
437            PublicGeneralPurposeDir::Documents => write!(f, "Documents"),
438            PublicGeneralPurposeDir::Download => write!(f, "Download"),
439        }
440    }
441}
442
443impl std::fmt::Display for PublicDir {
444    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
445        match self {
446            PublicDir::Image(p) => p.fmt(f),
447            PublicDir::Video(p) => p.fmt(f),
448            PublicDir::Audio(p) => p.fmt(f),
449            PublicDir::GeneralPurpose(p) => p.fmt(f),
450        }
451    }
452}
453
454macro_rules! impl_into_pubdir {
455    ($target: ident, $wrapper: ident) => {
456        impl From<$target> for PublicDir {
457            fn from(value: $target) -> Self {
458                Self::$wrapper(value)
459            }
460        }
461    };
462}
463impl_into_pubdir!(PublicImageDir, Image);
464impl_into_pubdir!(PublicVideoDir, Video);
465impl_into_pubdir!(PublicAudioDir, Audio);
466impl_into_pubdir!(PublicGeneralPurposeDir, GeneralPurpose);
467
468#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Deserialize, Serialize)]
469#[non_exhaustive]
470pub enum InitialLocation<'a> {
471
472    TopPublicDir,
473
474    PublicDir(PublicDir),
475    
476    DirInPublicDir {
477        base_dir: PublicDir,
478        relative_path: &'a str,
479    },
480
481    DirInPublicAppDir {
482        base_dir: PublicDir,
483        relative_path: &'a str,
484    }
485}
486
487impl<T: Into<PublicDir>> From<T> for InitialLocation<'_> {
488    fn from(value: T) -> Self {
489        InitialLocation::PublicDir(value.into())
490    }
491}