Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/platform/file_picker.rs
StratoSDK / crates / strato-ui-core / src / platform / file_picker.rs
1use std::{fmt, path::PathBuf, sync::Arc};
2 
3#[derive(Debug, Clone, thiserror::Error)]
4pub enum FilePickerError {
5 #[error("Failed to spawn file picker thread: {0}")]
6 ThreadSpawnFailed(Arc<std::io::Error>),
7 
8 #[error("File dialog failed: {0}")]
9 DialogFailed(String),
10}
11 
12// Define complex type here for the file picker callback.
13pub type FilePickerCallback =
14 Box<dyn FnOnce(Result<Vec<String>, FilePickerError>, &mut crate::AppContext) + Send + Sync>;
15 
16// Define callback type for save file picker - returns single path or None if cancelled
17pub type SaveFilePickerCallback =
18 Box<dyn FnOnce(Option<String>, &mut crate::AppContext) + Send + Sync>;
19 
20pub enum FileType {
21 Image,
22 Yaml,
23 Markdown,
24}
25 
26impl FileType {
27 /// List of supported file extensions for this file type.
28 pub fn extensions(&self) -> &[&str] {
29 match self {
30 FileType::Image => &["png", "jpg", "jpeg"],
31 FileType::Yaml => &["yaml", "yml"],
32 FileType::Markdown => &["md", "markdown"],
33 }
34 }
35 
36 /// Human-readable name for this general category of files.
37 pub fn display_name(&self) -> &str {
38 match self {
39 FileType::Image => "Image",
40 FileType::Yaml => "Yaml",
41 FileType::Markdown => "Markdown",
42 }
43 }
44}
45 
46impl fmt::Display for FileType {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 write!(f, "{}", self.display_name())
49 }
50}
51 
52/// Configuration for the file picker.
53///
54/// Not all configurations are supported on all platforms:
55/// * Linux can only show a single-file picker, a multi-file picker, or a single-directory picker.
56/// If choosing a folder is allowed ([`Self::allow_folder`] or [`Self::folders_only`]), a
57/// single-directory picker is shown, regardless of the other settings.
58/// * macOS supports any combination of allowing files, allowing folders, and allowing
59/// multi-select.
60pub struct FilePickerConfiguration {
61 allows_files: bool,
62 allows_folder: bool,
63 file_types: Vec<FileType>,
64 can_multi_select: bool,
65}
66 
67impl FilePickerConfiguration {
68 pub fn new() -> Self {
69 Self {
70 allows_files: true,
71 allows_folder: false,
72 file_types: Default::default(),
73 can_multi_select: false,
74 }
75 }
76 
77 /// Configure the file picker to allow choosing folders, in addition to files.
78 pub fn allow_folder(mut self) -> Self {
79 self.allows_folder = true;
80 self
81 }
82 
83 /// Configure the file picker to *only* allow choosing folders.
84 pub fn folders_only(mut self) -> Self {
85 self.allows_folder = true;
86 self.allows_files = false;
87 self
88 }
89 
90 /// Configure the file picker to allow selecting multiple files.
91 pub fn allow_multi_select(mut self) -> Self {
92 self.can_multi_select = true;
93 self
94 }
95 
96 pub fn set_allowed_file_types(mut self, file_types: Vec<FileType>) -> Self {
97 self.file_types = file_types;
98 self
99 }
100 
101 pub fn allows_files(&self) -> bool {
102 self.allows_files
103 }
104 
105 // TODO(CORE-2324): open file picker on Windows
106 
107 pub fn allows_folder(&self) -> bool {
108 self.allows_folder
109 }
110 
111 pub fn allows_multi_select(&self) -> bool {
112 self.can_multi_select
113 }
114 
115 pub fn file_types(&self) -> &Vec<FileType> {
116 &self.file_types
117 }
118}
119 
120impl Default for FilePickerConfiguration {
121 fn default() -> Self {
122 Self::new()
123 }
124}
125 
126#[derive(Default)]
127pub struct SaveFilePickerConfiguration {
128 /// Pre-fill the editable filename editor with this.
129 pub default_filename: Option<String>,
130 /// Open the picker into this directory location to start.
131 pub default_directory: Option<PathBuf>,
132}
133 
134impl SaveFilePickerConfiguration {
135 pub fn new() -> Self {
136 Self::default()
137 }
138 
139 pub fn with_default_filename(mut self, filename: String) -> Self {
140 self.default_filename = Some(filename);
141 self
142 }
143 
144 pub fn with_default_directory(mut self, directory: PathBuf) -> Self {
145 self.default_directory = Some(directory);
146 self
147 }
148}
149 
150#[cfg(test)]
151#[path = "file_picker_tests.rs"]
152mod tests;
153