file_upload.rs 3.1 KB

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