1
1
use crate :: models:: Yaml ;
2
2
use std:: io;
3
+
3
4
#[ cfg( not( target_arch = "wasm32" ) ) ]
4
5
use std:: fs;
5
6
#[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -13,11 +14,11 @@ use web_sys::{Blob, HtmlAnchorElement, Url, FileReader};
13
14
use wasm_bindgen_futures:: JsFuture ;
14
15
#[ cfg( target_arch = "wasm32" ) ]
15
16
use js_sys;
16
- #[ cfg( target_arch = "wasm32" ) ]
17
- use rfd;
18
17
19
18
use dioxus:: prelude:: * ;
20
19
use crate :: models:: MyLifeApp ;
20
+ use rfd:: FileDialog ;
21
+
21
22
22
23
#[ cfg( target_arch = "wasm32" ) ]
23
24
const DEFAULT_YAML : & str = include_str ! ( "../data/default.yaml" ) ;
@@ -43,33 +44,33 @@ impl NativeYamlManager {
43
44
#[ cfg( not( target_arch = "wasm32" ) ) ]
44
45
impl YamlManager for NativeYamlManager {
45
46
fn load_yaml ( & self , yaml_file : & str ) -> io:: Result < Yaml > {
46
- let yaml_path = std:: path:: Path :: new ( & self . data_folder ) . join ( yaml_file) ;
47
- let yaml_content = std:: fs:: read_to_string ( yaml_path) ?;
48
- let yaml: Yaml = serde_yaml:: from_str ( & yaml_content)
49
- . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: InvalidData , e) ) ?;
50
- Ok ( yaml)
47
+ let yaml_path = Path :: new ( & self . data_folder ) . join ( yaml_file) ;
48
+ let yaml_content = fs:: read_to_string ( yaml_path) ?;
49
+ serde_yaml:: from_str ( & yaml_content)
50
+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: InvalidData , e) )
51
51
}
52
52
53
53
fn save_yaml ( & self , yaml : & Yaml , yaml_file : & str ) -> io:: Result < ( ) > {
54
- let yaml_content = serde_yaml:: to_string ( & yaml)
54
+ let yaml_content = serde_yaml:: to_string ( yaml)
55
55
. map_err ( |e| io:: Error :: new ( io:: ErrorKind :: InvalidData , e) ) ?;
56
- let yaml_path = std :: path :: Path :: new ( & self . data_folder ) . join ( yaml_file) ;
57
- std :: fs:: write ( yaml_path, yaml_content)
56
+ let yaml_path = Path :: new ( & self . data_folder ) . join ( yaml_file) ;
57
+ fs:: write ( yaml_path, yaml_content)
58
58
}
59
-
60
59
fn get_available_yamls ( & self ) -> io:: Result < Vec < String > > {
61
60
let data_folder = Path :: new ( & self . data_folder ) ;
62
- Ok ( fs:: read_dir ( data_folder) ?
61
+ let yamls = fs:: read_dir ( data_folder) ?
63
62
. filter_map ( |entry| {
64
- let entry = entry. ok ( ) ?;
65
- let path = entry. path ( ) ;
66
- if path. extension ( ) ? == "yaml" {
67
- Some ( path. file_name ( ) ?. to_string_lossy ( ) . into_owned ( ) )
68
- } else {
69
- None
70
- }
63
+ entry. ok ( ) . and_then ( |e| {
64
+ let path = e. path ( ) ;
65
+ if path. extension ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "yaml" ) {
66
+ path. file_name ( ) . and_then ( |s| s. to_str ( ) ) . map ( String :: from)
67
+ } else {
68
+ None
69
+ }
70
+ } )
71
71
} )
72
- . collect ( ) )
72
+ . collect :: < Vec < String > > ( ) ;
73
+ Ok ( yamls)
73
74
}
74
75
}
75
76
@@ -83,7 +84,7 @@ impl YamlManager for WasmYamlManager {
83
84
}
84
85
85
86
fn save_yaml ( & self , yaml : & Yaml , _yaml_file : & str ) -> io:: Result < ( ) > {
86
- let yaml_content = serde_yaml:: to_string ( & yaml)
87
+ let yaml_content = serde_yaml:: to_string ( yaml)
87
88
. map_err ( |e| io:: Error :: new ( io:: ErrorKind :: InvalidData , e) ) ?;
88
89
89
90
let blob = Blob :: new_with_str_sequence ( & js_sys:: Array :: of1 ( & yaml_content. into ( ) ) )
@@ -129,40 +130,45 @@ pub fn get_yaml_manager() -> Box<dyn YamlManager> {
129
130
130
131
#[ cfg( target_arch = "wasm32" ) ]
131
132
pub fn get_default_yaml ( ) -> Yaml {
132
- load_yaml_from_yaml_content ( DEFAULT_YAML ) . expect ( "Failed to load default yaml" )
133
+ serde_yaml :: from_str ( DEFAULT_YAML ) . expect ( "Failed to load default yaml" )
133
134
}
134
135
135
- #[ cfg( target_arch = "wasm32" ) ]
136
- pub fn load_yaml_from_yaml_content ( yaml_content : & str ) -> Result < Yaml , String > {
137
- serde_yaml:: from_str ( yaml_content)
138
- . map_err ( |e| format ! ( "Failed to parse YAML: {:?}" , e) )
139
- }
140
-
141
- #[ cfg( target_arch = "wasm32" ) ]
142
136
pub async fn load_yaml_async ( ) -> Option < ( String , Yaml ) > {
143
- let file = rfd:: AsyncFileDialog :: new ( )
144
- . add_filter ( "YAML" , & [ "yaml" , "yml" ] )
145
- . pick_file ( )
146
- . await ?;
147
-
148
- let file_name = file. file_name ( ) ;
149
- let file_content = file. read ( ) . await ;
137
+ #[ cfg( target_arch = "wasm32" ) ]
138
+ {
139
+ let file = rfd:: AsyncFileDialog :: new ( )
140
+ . add_filter ( "YAML" , & [ "yaml" , "yml" ] )
141
+ . pick_file ( )
142
+ . await ?;
143
+
144
+ let file_name = file. file_name ( ) ;
145
+ let content = String :: from_utf8 ( file. read ( ) . await ) . ok ( ) ?;
146
+
147
+ serde_yaml:: from_str ( & content)
148
+ . map ( |yaml| Some ( ( file_name, yaml) ) )
149
+ . unwrap_or_else ( |e| {
150
+ log:: error!( "Failed to load yaml from YAML: {:?}" , e) ;
151
+ None
152
+ } )
153
+ }
150
154
151
- let blob = Blob :: new_with_u8_array_sequence ( & js_sys:: Array :: of1 ( & js_sys:: Uint8Array :: from ( & file_content[ ..] ) ) )
152
- . map_err ( |_| "Failed to create Blob" . to_string ( ) ) . ok ( ) ?;
155
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
156
+ {
157
+ use tokio:: fs;
153
158
154
- let reader = FileReader :: new ( ) . unwrap ( ) ;
155
- reader. read_as_text ( & blob) . unwrap ( ) ;
159
+ let file = rfd:: FileDialog :: new ( )
160
+ . add_filter ( "YAML" , & [ "yaml" , "yml" ] )
161
+ . pick_file ( ) ?;
156
162
157
- let promise = js_sys :: Promise :: resolve ( & reader . result ( ) . unwrap ( ) ) ;
158
- let content = JsFuture :: from ( promise ) . await . ok ( ) ?. as_string ( ) . unwrap ( ) ;
163
+ let file_name = file . file_name ( ) ? . to_string_lossy ( ) . into_owned ( ) ;
164
+ let content = fs :: read_to_string ( & file ) . await . ok ( ) ?;
159
165
160
- match load_yaml_from_yaml_content ( & content) {
161
- Ok ( yaml) => Some ( ( file_name, yaml) ) ,
162
- Err ( e ) => {
163
- log:: error!( "Failed to load yaml from YAML: {:?}" , e) ;
164
- None
165
- }
166
+ serde_yaml :: from_str ( & content)
167
+ . map ( | yaml| Some ( ( file_name, yaml) ) )
168
+ . unwrap_or_else ( |e| {
169
+ log:: error!( "Failed to load yaml from YAML: {:?}" , e) ;
170
+ None
171
+ } )
166
172
}
167
173
}
168
174
@@ -173,44 +179,85 @@ pub fn get_yaml() -> Yaml {
173
179
}
174
180
175
181
pub fn save_yaml ( yaml : & Yaml , yaml_file : & str ) -> Result < ( ) , String > {
176
- get_yaml_manager ( )
177
- . save_yaml ( yaml, yaml_file)
178
- . map_err ( |e| format ! ( "Failed to save yaml: {:?}" , e) )
179
- }
182
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
183
+ {
184
+ let yaml_content = serde_yaml:: to_string ( yaml)
185
+ . map_err ( |e| format ! ( "Failed to serialize YAML: {:?}" , e) ) ?;
186
+
187
+ let file_path = FileDialog :: new ( )
188
+ . set_file_name ( yaml_file)
189
+ . add_filter ( "YAML File" , & [ "yaml" , "yml" ] )
190
+ . save_file ( ) ;
191
+
192
+ if let Some ( path) = file_path {
193
+ std:: fs:: write ( path, yaml_content)
194
+ . map_err ( |e| format ! ( "Failed to save YAML file: {:?}" , e) ) ?;
195
+ Ok ( ( ) )
196
+ } else {
197
+ Err ( "File save cancelled" . to_string ( ) )
198
+ }
199
+ }
180
200
201
+ #[ cfg( target_arch = "wasm32" ) ]
202
+ {
203
+ get_yaml_manager ( )
204
+ . save_yaml ( yaml, yaml_file)
205
+ . map_err ( |e| format ! ( "Failed to save yaml: {:?}" , e) )
206
+ }
207
+ }
181
208
pub fn get_available_yamls ( ) -> Vec < String > {
182
209
get_yaml_manager ( )
183
210
. get_available_yamls ( )
184
211
. expect ( "Failed to get available yamls" )
185
212
}
186
213
187
- #[ cfg( not( target_arch = "wasm32" ) ) ]
188
214
pub fn import_yaml ( ) -> Option < ( String , Yaml ) > {
189
- let app_state = use_context :: < Signal < MyLifeApp > > ( ) ;
190
-
191
- if let Some ( file_path) = rfd:: FileDialog :: new ( )
192
- . add_filter ( "YAML" , & [ "yaml" , "yml" ] )
193
- . pick_file ( )
215
+ #[ cfg( not( target_arch = "wasm32" ) ) ]
194
216
{
195
- let file_name = file_path. file_name ( ) ?. to_str ( ) ?. to_string ( ) ;
196
- let content = fs:: read_to_string ( & file_path) . ok ( ) ?;
197
- let yaml: Yaml = serde_yaml:: from_str ( & content) . ok ( ) ?;
198
-
199
- let data_folder_string = app_state. read ( ) . data_folder . clone ( ) ;
200
- let data_folder = Path :: new ( & data_folder_string) ;
201
-
202
- let mut new_file_name = file_name. clone ( ) ;
203
- let mut counter = 1 ;
204
-
205
- while data_folder. join ( & new_file_name) . exists ( ) {
206
- new_file_name = format ! ( "{}-{}.yaml" , file_name. trim_end_matches( ".yaml" ) , counter) ;
207
- counter += 1 ;
217
+ let app_state = use_context :: < Signal < MyLifeApp > > ( ) ;
218
+
219
+ if let Some ( file_path) = rfd:: FileDialog :: new ( )
220
+ . add_filter ( "YAML" , & [ "yaml" , "yml" ] )
221
+ . pick_file ( )
222
+ {
223
+ let file_name = file_path. file_name ( ) ?. to_str ( ) ?. to_string ( ) ;
224
+ let content = fs:: read_to_string ( & file_path) . ok ( ) ?;
225
+ let yaml: Yaml = serde_yaml:: from_str ( & content) . ok ( ) ?;
226
+
227
+ let data_folder_string = app_state. read ( ) . data_folder . clone ( ) ;
228
+ let data_folder = Path :: new ( & data_folder_string) ;
229
+
230
+ let mut new_file_name = file_name. clone ( ) ;
231
+ let mut counter = 1 ;
232
+
233
+ while data_folder. join ( & new_file_name) . exists ( ) {
234
+ new_file_name = format ! ( "{}-{}.yaml" , file_name. trim_end_matches( ".yaml" ) , counter) ;
235
+ counter += 1 ;
236
+ }
237
+
238
+ fs:: copy ( file_path, data_folder. join ( & new_file_name) ) . ok ( ) ?;
239
+
240
+ Some ( ( new_file_name, yaml) )
241
+ } else {
242
+ None
208
243
}
244
+ }
245
+
246
+ #[ cfg( target_arch = "wasm32" ) ]
247
+ {
248
+ // For WASM, we'll use the load_yaml_async function
249
+ use wasm_bindgen_futures:: spawn_local;
209
250
210
- fs :: copy ( file_path , data_folder . join ( & new_file_name ) ) . ok ( ) ? ;
251
+ let ( tx , rx ) = std :: sync :: mpsc :: channel ( ) ;
211
252
212
- Some ( ( new_file_name, yaml) )
213
- } else {
214
- None
253
+ spawn_local ( async move {
254
+ if let Some ( ( name, yaml) ) = load_yaml_async ( ) . await {
255
+ tx. send ( Some ( ( name, yaml) ) ) . unwrap ( ) ;
256
+ } else {
257
+ tx. send ( None ) . unwrap ( ) ;
258
+ }
259
+ } ) ;
260
+
261
+ rx. recv ( ) . unwrap ( )
215
262
}
216
263
}
0 commit comments