max / audiofiles
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
1 file changed,
+76 insertions,
-0 deletions
| @@ -356,6 +356,12 @@ | |||
| 356 | 356 | } | |
| 357 | 357 | } | |
| 358 | 358 | } | |
| 359 | + | // A stand-in's way out. Two of goingson's twenty-seven have one, which | |
| 360 | + | // is why `act` is optional, and audiofiles' idle import screen is | |
| 361 | + | // another: "Nothing is being imported" with an Import... beside it. The | |
| 362 | + | // sentence is prose and the act is a control, so only the second is an | |
| 363 | + | // offer. | |
| 364 | + | Node::StandIn { act: Some(act), .. } => walk(&Node::Act(act.clone()), out), | |
| 359 | 365 | // A token that calls a route is a control drawn as a chip -- the filter | |
| 360 | 366 | // panel's twenty-four key pills are the site -- and one that calls | |
| 361 | 367 | // nothing is a badge. `Tag::action` is the whole of the difference, so | |
| @@ -525,6 +531,13 @@ | |||
| 525 | 531 | said = stripped.trim_end(); | |
| 526 | 532 | } | |
| 527 | 533 | } | |
| 534 | + | // A required field is drawn with a marker after its label. `Field::required` | |
| 535 | + | // is what the description says and `FieldStyle::required_marker` is how this | |
| 536 | + | // renderer shows it, so the asterisk is the same fact in the renderer's | |
| 537 | + | // spelling -- the caret's case again. | |
| 538 | + | if let Some(stripped) = said.strip_suffix('*') { | |
| 539 | + | said = stripped.trim_end(); | |
| 540 | + | } | |
| 528 | 541 | // An act carrying a key is drawn with it, as `label (key)`. The | |
| 529 | 542 | // description says the key on the act instead, so this is the same | |
| 530 | 543 | // normalization the caret gets: one fact, said two ways. | |
| @@ -1121,3 +1134,66 @@ | |||
| 1121 | 1134 | .in_a_window("Import folder") | |
| 1122 | 1135 | .assert(&described, &drawn); | |
| 1123 | 1136 | } | |
| 1137 | + | ||
| 1138 | + | /// The import flow's stages, in the states a test can stand one up in. | |
| 1139 | + | /// | |
| 1140 | + | /// The preflight has a test of its own because it is a modal rather than a | |
| 1141 | + | /// stage. This is the flow: one address whose answer depends on where the | |
| 1142 | + | /// import has got to, so a fidelity test that only visited one stage would say | |
| 1143 | + | /// almost nothing about it. | |
| 1144 | + | #[test] | |
| 1145 | + | fn the_import_flow_serves_what_it_describes_at_every_stage() { | |
| 1146 | + | type Reach = fn(&mut crate::state::BrowserState); | |
| 1147 | + | ||
| 1148 | + | let stages: [(&str, Reach); 4] = [ | |
| 1149 | + | ("idle", |_state| {}), | |
| 1150 | + | ("configuring", |state| { | |
| 1151 | + | state.import_wf.import_mode = crate::state::ImportMode::ConfigureImport { | |
| 1152 | + | source: std::path::PathBuf::from("/music/kits"), | |
| 1153 | + | source_name: "kits".to_owned(), | |
| 1154 | + | strategy: crate::import::ImportStrategy::NewVfs { | |
| 1155 | + | vfs_name: "kits".to_owned(), | |
| 1156 | + | }, | |
| 1157 | + | available_vfs: state.nav.vfs_list.to_vec(), | |
| 1158 | + | selected_merge_vfs_idx: 0, | |
| 1159 | + | new_vfs_name: "kits".to_owned(), | |
| 1160 | + | audio_file_count: 42, | |
| 1161 | + | }; | |
| 1162 | + | }), | |
| 1163 | + | ("copying", |state| { | |
| 1164 | + | state.import_wf.import_mode = crate::state::ImportMode::Importing { | |
| 1165 | + | total: 42, | |
| 1166 | + | completed: 7, | |
| 1167 | + | current_name: "kick.wav".to_owned(), | |
| 1168 | + | walking: false, | |
| 1169 | + | walking_count: 0, | |
| 1170 | + | total_bytes: 9_000_000, | |
| 1171 | + | loose_files: false, | |
| 1172 | + | }; | |
| 1173 | + | }), | |
| 1174 | + | ("stopped", |state| { | |
| 1175 | + | state.import_wf.import_mode = crate::state::ImportMode::OperationCancelled { | |
| 1176 | + | kind: crate::state::CancelKind::Import, | |
| 1177 | + | completed: 7, | |
| 1178 | + | total: 42, | |
| 1179 | + | destination: None, | |
| 1180 | + | }; | |
| 1181 | + | }), | |
| 1182 | + | ]; | |
| 1183 | + | ||
| 1184 | + | for (stage, reach) in stages { | |
| 1185 | + | let (mut state, _dir) = fixture(); | |
| 1186 | + | reach(&mut state); | |
| 1187 | + | ||
| 1188 | + | let described = described(&super::panel::described_screen(&state, "/import")); | |
| 1189 | + | let drawn = shipped(|ui| { | |
| 1190 | + | super::panel::draw_import(ui, &mut state); | |
| 1191 | + | }); | |
| 1192 | + | ||
| 1193 | + | described.addresses_resolve(); | |
| 1194 | + | // A full-screen mode drawn into the app's own pane, so no frame to | |
| 1195 | + | // discount -- the same terms as the tag queue and the filter panel. | |
| 1196 | + | Parity::strict().assert(&described, &drawn); | |
| 1197 | + | println!(" {stage}: ok"); | |
| 1198 | + | } | |
| 1199 | + | } |