fix(printers): page de test en auto-detection MIME, noms sanitaires compacts, actions en flex_row

La page de test est un template de banniere cups-filters (#PDF-BANNER), pas du PostScript: envoi en application/octet-stream pour laisser CUPS detecter le format. Le sanitiseur supprime crochets/parentheses et compacte les underscores (series [32C998] -> series_32C998). Les actions des details passent en flex_row pour eviter le debordement des boutons; bouton de confirmation du dialogue raccourci.
This commit is contained in:
Lionel DARNIS 2026-08-08 10:55:27 +02:00
parent 26dcaa6fd3
commit d5e57cc439
4 changed files with 31 additions and 15 deletions

View file

@ -113,7 +113,9 @@ pub fn print_test_page_sync(printer: &str) -> Result<(), String> {
let dest = cups_rs::get_destination(printer).map_err(|err| err.to_string())?; let dest = cups_rs::get_destination(printer).map_err(|err| err.to_string())?;
let job = cups_rs::create_job(&dest, "COSMIC Settings test page") let job = cups_rs::create_job(&dest, "COSMIC Settings test page")
.map_err(|err| err.to_string())?; .map_err(|err| err.to_string())?;
job.submit_file(TEST_PAGE, "application/postscript") // Let CUPS sniff the format: the test page is a cups-filters PDF banner
// template, not PostScript.
job.submit_file(TEST_PAGE, "application/octet-stream")
.map_err(|err| err.to_string()) .map_err(|err| err.to_string())
} }
@ -177,21 +179,29 @@ pub async fn set_enabled(name: &str, enabled: bool) -> Result<(), String> {
/// Sanitize a display name into a valid CUPS queue name and make it unique /// Sanitize a display name into a valid CUPS queue name and make it unique
/// against the current printer list. /// against the current printer list.
pub fn unique_name(raw: &str, existing: &[Printer]) -> String { pub fn unique_name(raw: &str, existing: &[Printer]) -> String {
let sanitized: String = raw let mut sanitized = String::with_capacity(raw.len());
.chars() for c in raw.chars() {
.map(|c| { if c.is_alphanumeric() {
if c.is_alphanumeric() || matches!(c, '-' | '_' | '.') { sanitized.push(c);
c } else if matches!(c, '[' | ']' | '(' | ')') {
} else { // Brackets usually wrap a model identifier; drop them so
'_' // "series [32C998]" becomes "series_32C998", not "series__32C998_".
} continue;
}) } else {
.collect(); sanitized.push('_');
}
}
let base = if sanitized.is_empty() { let base = sanitized
.split('_')
.filter(|part| !part.is_empty())
.collect::<Vec<_>>()
.join("_");
let base = if base.is_empty() {
"Printer".to_string() "Printer".to_string()
} else { } else {
sanitized base
}; };
let mut candidate = base.clone(); let mut candidate = base.clone();

View file

@ -112,7 +112,7 @@ impl page::Page<crate::pages::Message> for Page {
fn dialog(&self) -> Option<Element<'_, crate::pages::Message>> { fn dialog(&self) -> Option<Element<'_, crate::pages::Message>> {
let Dialog::RemovePrinter { name } = self.dialog.as_ref()?; let Dialog::RemovePrinter { name } = self.dialog.as_ref()?;
let confirm = widget::button::destructive(fl!("printers-remove")) let confirm = widget::button::destructive(fl!("printers-remove-confirm-button"))
.on_press(crate::pages::Message::from(Message::ConfirmRemove)); .on_press(crate::pages::Message::from(Message::ConfirmRemove));
let cancel = widget::button::standard(fl!("cancel")) let cancel = widget::button::standard(fl!("cancel"))
@ -711,7 +711,11 @@ fn selected_printer_section() -> Section<crate::pages::Message> {
.apply(Element::from), .apply(Element::from),
); );
column = column.add(widget::row::with_children(actions).spacing(spacing.space_s)); column = column.add(
widget::flex_row(actions)
.spacing(spacing.space_s)
.width(Length::Fill),
);
column.apply(Element::from) column.apply(Element::from)
}) })

View file

@ -675,6 +675,7 @@ printers-not-accepting = Not accepting jobs
printers-pause = Pause printers-pause = Pause
printers-remove = Remove printer printers-remove = Remove printer
printers-remove-confirm = Remove this printer? printers-remove-confirm = Remove this printer?
printers-remove-confirm-button = Remove
printers-remove-confirm-description = “{ $name }” will be removed from this system. Print jobs queued on it will be discarded. printers-remove-confirm-description = “{ $name }” will be removed from this system. Print jobs queued on it will be discarded.
printers-resume = Resume printers-resume = Resume
printers-state = State printers-state = State

View file

@ -463,6 +463,7 @@ printers-not-accepting = N'accepte pas les travaux
printers-pause = Suspendre printers-pause = Suspendre
printers-remove = Supprimer l'imprimante printers-remove = Supprimer l'imprimante
printers-remove-confirm = Supprimer cette imprimante ? printers-remove-confirm = Supprimer cette imprimante ?
printers-remove-confirm-button = Supprimer
printers-remove-confirm-description = « { $name } » sera supprimée du système. Les travaux en attente sur cette imprimante seront abandonnés. printers-remove-confirm-description = « { $name } » sera supprimée du système. Les travaux en attente sur cette imprimante seront abandonnés.
printers-resume = Reprendre printers-resume = Reprendre
printers-state = État printers-state = État