file_upload.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #![allow(unused)]
  2. use serde::Deserialize;
  3. use std::{path::PathBuf, str::FromStr};
  4. #[derive(Debug, Deserialize)]
  5. pub(crate) struct FileDialogRequest {
  6. #[serde(default)]
  7. accept: Option<String>,
  8. multiple: bool,
  9. directory: bool,
  10. pub event: String,
  11. pub target: usize,
  12. pub bubbles: bool,
  13. }
  14. #[allow(unused)]
  15. impl FileDialogRequest {
  16. #[cfg(not(any(
  17. target_os = "windows",
  18. target_os = "macos",
  19. target_os = "linux",
  20. target_os = "dragonfly",
  21. target_os = "freebsd",
  22. target_os = "netbsd",
  23. target_os = "openbsd"
  24. )))]
  25. pub(crate) fn get_file_event(&self) -> Vec<PathBuf> {
  26. vec![]
  27. }
  28. #[cfg(any(
  29. target_os = "windows",
  30. target_os = "macos",
  31. target_os = "linux",
  32. target_os = "dragonfly",
  33. target_os = "freebsd",
  34. target_os = "netbsd",
  35. target_os = "openbsd"
  36. ))]
  37. pub(crate) fn get_file_event(&self) -> Vec<PathBuf> {
  38. fn get_file_event_for_folder(
  39. request: &FileDialogRequest,
  40. dialog: rfd::FileDialog,
  41. ) -> Vec<PathBuf> {
  42. if request.multiple {
  43. dialog.pick_folders().into_iter().flatten().collect()
  44. } else {
  45. dialog.pick_folder().into_iter().collect()
  46. }
  47. }
  48. fn get_file_event_for_file(
  49. request: &FileDialogRequest,
  50. mut dialog: rfd::FileDialog,
  51. ) -> Vec<PathBuf> {
  52. let filters: Vec<_> = request
  53. .accept
  54. .as_deref()
  55. .unwrap_or_default()
  56. .split(',')
  57. .filter_map(|s| Filters::from_str(s).ok())
  58. .collect();
  59. let file_extensions: Vec<_> = filters
  60. .iter()
  61. .flat_map(|f| f.as_extensions().into_iter())
  62. .collect();
  63. dialog = dialog.add_filter("name", file_extensions.as_slice());
  64. let files: Vec<_> = if request.multiple {
  65. dialog.pick_files().into_iter().flatten().collect()
  66. } else {
  67. dialog.pick_file().into_iter().collect()
  68. };
  69. files
  70. }
  71. let dialog = rfd::FileDialog::new();
  72. if self.directory {
  73. get_file_event_for_folder(self, dialog)
  74. } else {
  75. get_file_event_for_file(self, dialog)
  76. }
  77. }
  78. }
  79. enum Filters {
  80. Extension(String),
  81. Mime(String),
  82. Audio,
  83. Video,
  84. Image,
  85. }
  86. impl Filters {
  87. fn as_extensions(&self) -> Vec<&str> {
  88. match self {
  89. Filters::Extension(extension) => vec![extension.as_str()],
  90. Filters::Mime(_) => vec![],
  91. Filters::Audio => vec!["mp3", "wav", "ogg"],
  92. Filters::Video => vec!["mp4", "webm"],
  93. Filters::Image => vec!["png", "jpg", "jpeg", "gif", "webp"],
  94. }
  95. }
  96. }
  97. impl FromStr for Filters {
  98. type Err = String;
  99. fn from_str(s: &str) -> Result<Self, Self::Err> {
  100. if let Some(extension) = s.strip_prefix('.') {
  101. Ok(Filters::Extension(extension.to_string()))
  102. } else {
  103. match s {
  104. "audio/*" => Ok(Filters::Audio),
  105. "video/*" => Ok(Filters::Video),
  106. "image/*" => Ok(Filters::Image),
  107. _ => Ok(Filters::Mime(s.to_string())),
  108. }
  109. }
  110. }
  111. }