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