diff --git a/crates/ui-egui/src/a11y_ui.rs b/crates/ui-egui/src/a11y_ui.rs index 1e7ab215..c688c58f 100644 --- a/crates/ui-egui/src/a11y_ui.rs +++ b/crates/ui-egui/src/a11y_ui.rs @@ -45,6 +45,9 @@ impl Default for A11yOptions { #[derive(Clone, Debug, Default)] pub struct A11yState { pub report: Option<(DocId, Report)>, + /// The prior check of the same document with the same checker options. + pub previous: Option<(DocId, Report)>, + pub options: Option, /// Collapsed categories and expanded rules. pub collapsed: BTreeSet, pub expanded: BTreeSet, @@ -191,6 +194,26 @@ pub(crate) fn panel(ui: &mut egui::Ui, t: &Tokens, state: &mut A11yState, doc: D } }); }); + if let Some((_, previous)) = state.previous.as_ref().filter(|(d, _)| *d == doc) { + egui::CollapsingHeader::new(tl!("Compare")).default_open(true).show(ui, |ui| { + for status in [Status::Passed, Status::Failed, Status::Manual, Status::Skipped] { + ui.label(format!("{}: {} → {}", tl!(status.label()), previous.count(status), report.count(status))); + } + for current in &report.results { + let Some(prior) = previous.result(current.rule) else { continue }; + if prior.status != current.status || prior.findings.len() != current.findings.len() { + ui.label(format!( + "{}: {} ({}) → {} ({})", + tl!(current.rule.name()), + tl!(prior.status.label()), + prior.findings.len(), + tl!(current.status.label()), + current.findings.len() + )); + } + } + }); + } ui.add_space(6.0); for c in Category::ALL { let rules: Vec<_> = report.in_category(c).collect(); @@ -331,6 +354,9 @@ impl PdfCraftApp { r.findings.clear(); } let failed = report.count(Status::Failed); + self.a11y.previous = + if self.a11y.options.as_ref() == Some(&options) { self.a11y.report.take().filter(|(prior_id, _)| *prior_id == id) } else { None }; + self.a11y.options = Some(options); self.a11y.report = Some((id, report)); self.right = Some(RightPanel::Accessibility); self.notify(if failed == 0 { diff --git a/crates/ui-egui/tests/accessibility.rs b/crates/ui-egui/tests/accessibility.rs index f8c69c81..967dd6a5 100644 --- a/crates/ui-egui/tests/accessibility.rs +++ b/crates/ui-egui/tests/accessibility.rs @@ -61,10 +61,13 @@ fn checking_fixing_skipping_and_reporting() { h.get_by_label("Fix").click(); h.run_steps(3); assert_eq!(status(&h, Rule::Title), Status::Passed); + assert_eq!(h.state().a11y.previous.as_ref().unwrap().1.result(Rule::Title).unwrap().status, Status::Failed); assert!(matches!(h.state().dialog, Some(Dialog::Properties(_)))); assert_eq!(h.state().window_title, "notes — PdfCraft"); h.state_mut().dialog = None; h.run_steps(2); + h.get_by_label("Compare"); + h.get_by_label_contains("Title: Failed (2) → Passed (0)"); // Skip a rule; it stays skipped when checking again. right_click(&mut h, "Tagged PDF - Failed"); h.get_by_label("Skip Rule").click(); diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index e9144a04..e6e15139 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -8413,9 +8413,9 @@ tier = "P1" milestone = "M12" status = "shipped" commands = ["a11y.check"] -tools = ["accessibility_fix"] -evidence = ["crates/ui-egui/tests/accessibility.rs::checking_fixing_skipping_and_reporting", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools"] -notes = "right-click a rule: Fix (language via Document Properties, title, tab order), Skip Rule (kept on Check Again), Explain, Check Again, Show Report, Options" +tools = ["accessibility_fix", "accessibility_review_record"] +evidence = ["crates/ui-egui/tests/accessibility.rs::checking_fixing_skipping_and_reporting", "crates/automation/tests/automation.rs::accessibility_check_report_and_fixes_through_tools", "crates/automation/tests/automation.rs::accessibility_review_record_compares_two_versions_without_changing_them"] +notes = "right-click a rule: Fix (language via Document Properties, title, tab order), Skip Rule (kept on Check Again), Explain, Check Again, Show Report, Options. The panel compares outcome counts and changed rules with the previous check of the same document and options; the headless review record compares two open revisions." [[feature]] id = "a11y.rule-permission-flag"