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}