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}