Skip to main content

max / audiofiles

Take quasi 0.88.0: the filters and previews ask rather than write quasicoherent aeb44860. Five controls said Field::writes for something that writes nothing: the search box and its scope, the bulk rename pattern, the gain preview, and the review list's order. A preview route mutates nothing by construction -- /bulk/rename and /edit/gain are the form actions beside them, and they are the only things there that touch a sample -- and the two filters change what the browser shows and no more. The scope and order radios take Consult::at_once; the search box, the pattern and the gain take the typing wait, which is what keeps a drag from asking once a frame. Two sites that look like these and are not, so they stay writes: the tag filter's box and the classifier's policy box echo what is typed into panel state, and /classifier/policies/add reads that state rather than a payload, so a debounce there would add an empty policy to a reader who typed and pressed Add.
Author: Max Johnson <me@maxj.phd> · 2026-08-30 21:03 UTC
Signed with PGP, not checked
Commit: 8491f5afc74b5b1b1ed22088954e4399fc2291f4
Parent: a81715c
6 files changed, +58 insertions, -47 deletions
M Cargo.lock +30 -30
@@ -4256,7 +4256,7 @@
4256 4256
4257 4257 [[package]]
4258 4258 name = "quasi-immediate"
4259 - version = "0.87.0"
4259 + version = "0.88.0"
4260 4260 dependencies = [
4261 4261 "docengine",
4262 4262 "egui",
@@ -4267,7 +4267,7 @@
4267 4267
4268 4268 [[package]]
4269 4269 name = "quasi-router"
4270 - version = "0.87.0"
4270 + version = "0.88.0"
4271 4271 dependencies = [
4272 4272 "makeover-layout",
4273 4273 ]
@@ -7557,32 +7557,8 @@
7557 7557 ]
7558 7558
7559 7559 [[patch.unused]]
7560 - name = "quasi-axum"
7561 - version = "0.87.0"
7562 -
7563 - [[patch.unused]]
7564 - name = "quasi-basics"
7565 - version = "0.87.0"
7566 -
7567 - [[patch.unused]]
7568 - name = "quasi-http"
7569 - version = "0.87.0"
7570 -
7571 - [[patch.unused]]
7572 - name = "quasi-notifs"
7573 - version = "0.87.0"
7574 -
7575 - [[patch.unused]]
7576 - name = "quasi-store"
7577 - version = "0.1.0"
7578 -
7579 - [[patch.unused]]
7580 - name = "quasi-tauri"
7581 - version = "0.87.0"
7582 -
7583 - [[patch.unused]]
7584 - name = "quasi-webview"
7585 - version = "0.87.0"
7560 + name = "quasi-type"
7561 + version = "0.1.3"
7586 7562
7587 7563 [[patch.unused]]
7588 7564 name = "kberg"
@@ -7597,5 +7573,29 @@
7597 7573 version = "0.1.0"
7598 7574
7599 7575 [[patch.unused]]
7600 - name = "quasi-type"
7601 - version = "0.1.3"
7576 + name = "quasi-axum"
7577 + version = "0.88.0"
7578 +
7579 + [[patch.unused]]
7580 + name = "quasi-basics"
7581 + version = "0.88.0"
7582 +
7583 + [[patch.unused]]
7584 + name = "quasi-http"
7585 + version = "0.88.0"
7586 +
7587 + [[patch.unused]]
7588 + name = "quasi-notifs"
7589 + version = "0.88.0"
7590 +
7591 + [[patch.unused]]
7592 + name = "quasi-store"
7593 + version = "0.1.0"
7594 +
7595 + [[patch.unused]]
7596 + name = "quasi-tauri"
7597 + version = "0.88.0"
7598 +
7599 + [[patch.unused]]
7600 + name = "quasi-webview"
7601 + version = "0.88.0"
M Cargo.toml +2 -2
@@ -26,8 +26,8 @@
26 26 # The described screens, which are audiofiles-browser's screens. By git URL with
27 27 # a version requirement, per the tree's rule for cross-repo deps. They were
28 28 # behind a `quasi` feature until 2026-08-25, when the last flip landed.
29 - quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.87" }
30 - quasi-immediate = { git = "https://makenot.work/git/max/quasi.git", version = "0.87" }
29 + quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" }
30 + quasi-immediate = { git = "https://makenot.work/git/max/quasi.git", version = "0.88" }
31 31 egui = { version = "0.35", default-features = false, features = ["default_fonts"] }
32 32 egui_extras = { version = "0.35", default-features = false }
33 33 eframe = { version = "0.35", default-features = false, features = ["default_fonts", "glow"] }
@@ -65,8 +65,8 @@
65 65
66 66 use quasi_router::layout::{FieldKind, Tone};
67 67 use quasi_router::{
68 - Act, Action, Cell, Cells, Choice, Column, Field, Node, Outcome, RegionKind, Request, Response,
69 - Rest, RouteError, Router, Screen, Slot, Tag,
68 + Act, Action, Cell, Cells, Choice, Column, Consult, Field, Node, Outcome, RegionKind, Request,
69 + Response, Rest, RouteError, Router, Screen, Slot, Tag,
70 70 };
71 71
72 72 use super::{Chosen, Panels};
@@ -406,7 +406,10 @@
406 406 Field::new(FieldKind::Text, PATTERN, "Pattern")
407 407 .value(pattern)
408 408 .hint("{name}_{bpm}")
409 - .writes(Action::post("/bulk/rename/preview")),
409 + // The preview is an answer about the pattern, not a rename:
410 + // `/bulk/rename` is the form's own action and is the only
411 + // thing here that moves a file.
412 + .consulting(Consult::new(Action::post("/bulk/rename/preview"))),
410 413 ],
411 414 submit: "Rename".to_owned(),
412 415 action: Action::post("/bulk/rename"),
@@ -70,7 +70,7 @@
70 70 //! `Field`'s two message slots are help and error with nothing between, and this
71 71 //! is its third measured site after the export screen's re-encoding warning.
72 72 //!
73 - //! The workaround is the rename preview's: `Field::writes` answers a fragment
73 + //! The workaround is the rename preview's: `Field::consults` answers a fragment
74 74 //! into a region beside the field. It costs a route and a region for what wants
75 75 //! to be a member.
76 76 //!
@@ -98,8 +98,8 @@
98 98
99 99 use quasi_router::layout::{FieldKind, Tone};
100 100 use quasi_router::{
101 - Act, Action, Choice, Field, Figure, Node, RegionKind, Request, Response, RouteError, Router,
102 - Screen, Slot,
101 + Act, Action, Choice, Consult, Field, Figure, Node, RegionKind, Request, Response, RouteError,
102 + Router, Screen, Slot,
103 103 };
104 104
105 105 use audiofiles_core::edit::FadeCurve;
@@ -310,8 +310,11 @@
310 310 .step("0.1")
311 311 .value("0")
312 312 // The clipping consequence, which the field cannot carry
313 - // itself. See the module header, `5672cad4`.
314 - .writes(Action::post("/edit/gain/preview")),
313 + // itself. See the module header, `5672cad4`. A question
314 + // rather than a write: nothing is applied until the form
315 + // is submitted. The wait is what keeps a drag from asking
316 + // once a frame.
317 + .consulting(Consult::new(Action::post("/edit/gain/preview"))),
315 318 ],
316 319 submit: "Apply gain".to_owned(),
317 320 action: Action::post("/edit/gain"),
@@ -348,7 +351,7 @@
348 351
349 352 /// What the gain about to be applied would do to the peak.
350 353 ///
351 - /// Its own node so `Field::writes` can answer it as a fragment while the
354 + /// Its own node so `Field::consults` can answer it as a fragment while the
352 355 /// control is being moved, which is the rename preview's arrangement.
353 356 fn clips(peak: Option<f64>, gain: f64) -> Node {
354 357 let Some(peak) = peak else {
@@ -155,7 +155,7 @@
155 155
156 156 use quasi_router::layout::{Family, FieldKind, Readiness, Tone};
157 157 use quasi_router::{
158 - Accepted, Act, Action, Choice, Field, Figure, Locating, Meter, Node, Outcome, Prose,
158 + Accepted, Act, Action, Choice, Consult, Field, Figure, Locating, Meter, Node, Outcome, Prose,
159 159 RegionKind, Request, Response, RouteError, Router, Row, Screen, Slot, Sought,
160 160 };
161 161
@@ -1339,7 +1339,9 @@
1339 1339 .collect(),
1340 1340 )
1341 1341 .value(order.as_str())
1342 - .writes(Action::post("/import/review/order")),
1342 + // Sorting the review list changes what is on screen and nothing else,
1343 + // so it asks rather than writes, and a radio has nothing to wait out.
1344 + .consulting(Consult::at_once(Action::post("/import/review/order"))),
1343 1345 )));
1344 1346
1345 1347 if items.is_empty() {
@@ -87,8 +87,8 @@
87 87
88 88 use quasi_router::layout::{self, FieldKind, Priority, Tone, Width};
89 89 use quasi_router::{
90 - Act, Action, Choice, Field, Node, RegionKind, Request, Response, RouteError, Router, Screen,
91 - Slot,
90 + Act, Action, Choice, Consult, Field, Node, RegionKind, Request, Response, RouteError, Router,
91 + Screen, Slot,
92 92 };
93 93
94 94 use super::{Panel, Panels, Where};
@@ -509,7 +509,10 @@
509 509 // no pixel -- and it is the difference between a row that
510 510 // happens to look right and one that says what it means.
511 511 .width(Width::Fill)
512 - .writes(Action::post("/search")),
512 + // A question and not a write: it narrows what the browser
513 + // is showing and nothing is stored. The wait is the typing
514 + // wait, so a query typed in one go asks once.
515 + .consulting(Consult::new(Action::post("/search"))),
513 516 )),
514 517 Priority::Essential,
515 518 )
@@ -533,7 +536,7 @@
533 536 } else {
534 537 "folder"
535 538 })
536 - .writes(Action::post("/search/scope")),
539 + .consulting(Consult::at_once(Action::post("/search/scope"))),
537 540 )),
538 541 Priority::Secondary,
539 542 );