max / audiofiles
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
4 files changed,
+62 insertions,
-25 deletions
| @@ -81,18 +81,19 @@ | |||
| 81 | 81 | //! | invalid-tag warning per folder | yes | `tags::validate_tag` over what was typed, and pure | | |
| 82 | 82 | //! | BPM range and top keys over the batch | yes | arithmetic over the results the screen already carries | | |
| 83 | 83 | //! | **rate and ETA** | no | a rolling wall-clock buffer, which is a fact about this machine | | |
| 84 | - | //! | **`Import files...`**, and two doors not converted yet | no | see below | | |
| 84 | + | //! | **`Import files...`**, and the source door not converted yet | no | see below | | |
| 85 | 85 | //! | **↑/↓ walking the review list** | no | a key bound to "the next row of a list", which `Chrome` cannot say | | |
| 86 | 86 | //! | |
| 87 | 87 | //! The pickers are the sharper half. `Import folder...`, `Quick import | |
| 88 | 88 | //! folder...`, `Import files...` and `Change...` each open a native dialog and | |
| 89 | 89 | //! then act, which this header filed as consumers five to eight of | |
| 90 | 90 | //! `quasi:vocabulary:host-save-location`. That gap closed in quasi 0.60 | |
| 91 | - | //! (`ec92f9cb`) and `Import folder...` is converted: [`open_folder`](fn@open_folder) | |
| 92 | - | //! says a folder is wanted and [`folder_chosen`](fn@folder_chosen) sets the | |
| 93 | - | //! wizard up on the answer. | |
| 91 | + | //! (`ec92f9cb`) and the two folder doors are converted: | |
| 92 | + | //! [`open_folder`](fn@open_folder) and [`open_quickly`](fn@open_quickly) say a | |
| 93 | + | //! folder is wanted, and the answer lands on a second address that does the | |
| 94 | + | //! work. | |
| 94 | 95 | //! | |
| 95 | - | //! The other three still hand off, and a route that hands off to the host has | |
| 96 | + | //! The other two still hand off, and a route that hands off to the host has | |
| 96 | 97 | //! nothing true to answer. [`Outcome`](quasi_router::Outcome) is `Screen`, | |
| 97 | 98 | //! `Fragment`, `Goto` or `Over`, and none of them is "nothing here changed". | |
| 98 | 99 | //! They answer `Goto(/import)`, right by the time the picker returns and a | |
| @@ -223,6 +224,7 @@ | |||
| 223 | 224 | .post("/import/open/folder", open_folder) | |
| 224 | 225 | .post("/import/open/folder/chosen", folder_chosen) | |
| 225 | 226 | .post("/import/open/quick", open_quickly) | |
| 227 | + | .post("/import/open/quick/chosen", quick_chosen) | |
| 226 | 228 | .post("/import/open/files", open_files) | |
| 227 | 229 | .post("/import/source", change_source) | |
| 228 | 230 | .post("/import/set/{decision}", decide) | |
| @@ -400,8 +402,26 @@ | |||
| 400 | 402 | } | |
| 401 | 403 | ||
| 402 | 404 | /// `POST /import/open/quick` | |
| 403 | - | fn open_quickly(state: &Panels<'_>, _request: Request) -> Result<Response, RouteError> { | |
| 404 | - | state.importing.open_quickly(); | |
| 405 | + | /// | |
| 406 | + | /// Says a folder is wanted and leaves the picker to the host. Indexing it is | |
| 407 | + | /// [`quick_chosen`](fn@quick_chosen)'s, on the answer. | |
| 408 | + | fn open_quickly(_state: &Panels<'_>, _request: Request) -> Result<Response, RouteError> { | |
| 409 | + | Ok(Response::locate(Locating::folder( | |
| 410 | + | "Quick import folder", | |
| 411 | + | Action::post("/import/open/quick/chosen"), | |
| 412 | + | FOLDER, | |
| 413 | + | ))) | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | /// `POST /import/open/quick/chosen` | |
| 417 | + | /// | |
| 418 | + | /// Empty means the reader backed out of the picker, which is the same second | |
| 419 | + | /// guard [`folder_chosen`](fn@folder_chosen) carries. | |
| 420 | + | fn quick_chosen(state: &Panels<'_>, request: Request) -> Result<Response, RouteError> { | |
| 421 | + | let folder = request.payload.get(FOLDER).unwrap_or_default(); | |
| 422 | + | if !folder.is_empty() { | |
| 423 | + | state.importing.open_quickly(folder); | |
| 424 | + | } | |
| 405 | 425 | Ok(handed_off()) | |
| 406 | 426 | } | |
| 407 | 427 |
| @@ -842,8 +842,8 @@ | |||
| 842 | 842 | CancelImport, | |
| 843 | 843 | /// Set the wizard up on this folder, which the reader picked. | |
| 844 | 844 | ImportFolder(std::path::PathBuf), | |
| 845 | - | /// Ask the host for a folder, then index it with no questions asked. | |
| 846 | - | OpenQuickImport, | |
| 845 | + | /// Index this folder with no questions asked, the reader having picked it. | |
| 846 | + | QuickImportFolder(std::path::PathBuf), | |
| 847 | 847 | /// Ask the host for files, then merge them into the vault that is open. | |
| 848 | 848 | OpenImportFiles, | |
| 849 | 849 | /// Ask the host for a different folder for the import being configured. | |
| @@ -3802,8 +3802,8 @@ | |||
| 3802 | 3802 | /// Set the wizard up on this folder. | |
| 3803 | 3803 | fn open_folder(&self, folder: &str); | |
| 3804 | 3804 | ||
| 3805 | - | /// Pick a folder, then index it with no questions asked. | |
| 3806 | - | fn open_quickly(&self); | |
| 3805 | + | /// Index this folder with no questions asked. | |
| 3806 | + | fn open_quickly(&self, folder: &str); | |
| 3807 | 3807 | ||
| 3808 | 3808 | /// Pick files, then merge them into the vault that is open. | |
| 3809 | 3809 | fn open_files(&self); | |
| @@ -4097,8 +4097,8 @@ | |||
| 4097 | 4097 | self.push(Intent::ImportFolder(std::path::PathBuf::from(folder))); | |
| 4098 | 4098 | } | |
| 4099 | 4099 | ||
| 4100 | - | fn open_quickly(&self) { | |
| 4101 | - | self.push(Intent::OpenQuickImport); | |
| 4100 | + | fn open_quickly(&self, folder: &str) { | |
| 4101 | + | self.push(Intent::QuickImportFolder(std::path::PathBuf::from(folder))); | |
| 4102 | 4102 | } | |
| 4103 | 4103 | ||
| 4104 | 4104 | fn open_files(&self) { |
| @@ -1049,11 +1049,7 @@ | |||
| 1049 | 1049 | // `OpenImportFiles` opens its own, for the reason `importing`'s | |
| 1050 | 1050 | // header gives. | |
| 1051 | 1051 | Intent::ImportFolder(folder) => state.show_import_options(folder), | |
| 1052 | - | Intent::OpenQuickImport => { | |
| 1053 | - | state | |
| 1054 | - | .dialogs | |
| 1055 | - | .pick_folder("Quick import folder", BrowserState::quick_import_folder); | |
| 1056 | - | } | |
| 1052 | + | Intent::QuickImportFolder(folder) => state.quick_import_folder(folder), | |
| 1057 | 1053 | Intent::OpenImportFiles => { | |
| 1058 | 1054 | state.dialogs.pick_files( | |
| 1059 | 1055 | "Import files", |
| @@ -5756,7 +5756,7 @@ | |||
| 5756 | 5756 | fn accept(&self, _again: bool) {} | |
| 5757 | 5757 | fn cancel(&self) {} | |
| 5758 | 5758 | fn open_folder(&self, _folder: &str) {} | |
| 5759 | - | fn open_quickly(&self) {} | |
| 5759 | + | fn open_quickly(&self, _folder: &str) {} | |
| 5760 | 5760 | fn open_files(&self) {} | |
| 5761 | 5761 | fn change_source(&self) {} | |
| 5762 | 5762 | fn decide(&self, _decision: Decision, _value: &str) {} | |
| @@ -6416,8 +6416,8 @@ | |||
| 6416 | 6416 | self.say(format!("open:folder {folder}")); | |
| 6417 | 6417 | } | |
| 6418 | 6418 | ||
| 6419 | - | fn open_quickly(&self) { | |
| 6420 | - | self.say("open:quick"); | |
| 6419 | + | fn open_quickly(&self, folder: &str) { | |
| 6420 | + | self.say(format!("open:quick {folder}")); | |
| 6421 | 6421 | } | |
| 6422 | 6422 | ||
| 6423 | 6423 | fn open_files(&self) { | |
| @@ -8158,10 +8158,7 @@ | |||
| 8158 | 8158 | fn the_doors_hand_off_to_the_host_and_say_where_the_answer_will_be() { | |
| 8159 | 8159 | // No outcome means "nothing here changed", so they answer the flow, which | |
| 8160 | 8160 | // is right by the time the picker returns. See the module header. | |
| 8161 | - | for (address, expected) in [ | |
| 8162 | - | ("/import/open/quick", "open:quick"), | |
| 8163 | - | ("/import/open/files", "open:files"), | |
| 8164 | - | ] { | |
| 8161 | + | for (address, expected) in [("/import/open/files", "open:files")] { | |
| 8165 | 8162 | let import = FakeImport::default(); | |
| 8166 | 8163 | let response = importing(&import, Request::post(address)).unwrap(); | |
| 8167 | 8164 | assert!( | |
| @@ -8199,6 +8196,30 @@ | |||
| 8199 | 8196 | assert!(import.answered().is_empty()); | |
| 8200 | 8197 | } | |
| 8201 | 8198 | ||
| 8199 | + | #[test] | |
| 8200 | + | fn the_quick_door_asks_the_host_for_a_folder_and_indexes_the_answer() { | |
| 8201 | + | let import = FakeImport::default(); | |
| 8202 | + | let response = importing(&import, Request::post("/import/open/quick")).unwrap(); | |
| 8203 | + | let Outcome::Locate(asking) = &response.outcome else { | |
| 8204 | + | panic!("expected an ask, got {:?}", response.outcome); | |
| 8205 | + | }; | |
| 8206 | + | assert_eq!(asking.answers.route(), Some("/import/open/quick/chosen")); | |
| 8207 | + | assert_eq!(asking.sought, quasi_router::Sought::Folder); | |
| 8208 | + | assert!(import.answered().is_empty(), "the ask indexed something"); | |
| 8209 | + | ||
| 8210 | + | let answered = Request::post("/import/open/quick/chosen") | |
| 8211 | + | .sending(Params::new().with("folder".to_owned(), "/mnt/kit".to_owned())); | |
| 8212 | + | importing(&import, answered).unwrap(); | |
| 8213 | + | assert_eq!(import.answered(), ["open:quick /mnt/kit"]); | |
| 8214 | + | } | |
| 8215 | + | ||
| 8216 | + | #[test] | |
| 8217 | + | fn backing_out_of_the_quick_picker_indexes_nothing() { | |
| 8218 | + | let import = FakeImport::default(); | |
| 8219 | + | importing(&import, Request::post("/import/open/quick/chosen")).unwrap(); | |
| 8220 | + | assert!(import.answered().is_empty()); | |
| 8221 | + | } | |
| 8222 | + | ||
| 8202 | 8223 | #[test] | |
| 8203 | 8224 | fn the_source_can_only_be_changed_while_there_is_one_being_configured() { | |
| 8204 | 8225 | let configuring = FakeImport::at(configuring(Strategy::Flat, "", &[])); |