Skip to main content

max / audiofiles

5.3 KB · 135 lines History Blame Raw
1 use egui;
2
3 use crate::state::{BrowserState, ConfirmAction, ImportMode};
4
5 use super::super::{theme, widgets};
6
7 /// Draw the post-import error review screen.
8 pub fn draw_review_errors(ui: &mut egui::Ui, state: &mut BrowserState) {
9 if !matches!(state.import_mode, ImportMode::ReviewErrors) {
10 return;
11 }
12
13 egui::CentralPanel::default().show_inside(ui, |ui| {
14 ui.heading("Import Summary");
15 ui.add_space(theme::space::LG);
16
17 let analysis_count = state.analysis_errors.len();
18 let import_count = state.import_file_errors.len();
19
20 // Analysis errors: files in the store that couldn't be analyzed.
21 // M-13: explanatory copy distinguishes this category from the
22 // import-error category below (recoverable here, informational there).
23 if analysis_count > 0 {
24 ui.label(
25 egui::RichText::new(format!(
26 "{analysis_count} file{} failed analysis",
27 if analysis_count == 1 { "" } else { "s" },
28 ))
29 .strong()
30 .color(theme::accent_red()),
31 );
32 ui.label(
33 egui::RichText::new(
34 "These files are in the library but couldn't be analysed. \
35 You can remove them, ignore them, or re-analyse later.",
36 )
37 .small()
38 .color(theme::text_muted()),
39 );
40 ui.add_space(theme::space::SM);
41
42 let mut remove_request: Option<(usize, String)> = None;
43 egui::ScrollArea::vertical()
44 .id_salt("analysis_errors")
45 .max_height(200.0)
46 .show(ui, |ui| {
47 for (i, err) in state.analysis_errors.iter().enumerate() {
48 ui.horizontal(|ui| {
49 // Row labels rendered in primary text. The section
50 // heading carries the red emphasis (M-13); per-row
51 // red on top reads as a wall of failure rather
52 // than a list of files to triage.
53 ui.label(&err.name);
54 ui.label(
55 egui::RichText::new(&err.error)
56 .small()
57 .color(theme::text_secondary()),
58 );
59 if widgets::danger_small_button(ui, "Remove").clicked() {
60 remove_request = Some((i, err.name.clone()));
61 }
62 });
63 }
64 });
65
66 // Route per-row Remove through the confirm dialog rather than
67 // deleting on click (C-2). Detail line names the specific file.
68 if let Some((idx, name)) = remove_request {
69 state.pending_confirm = Some(ConfirmAction::RemoveFailedSamples {
70 single_index: Some(idx),
71 count: 1,
72 name: Some(name),
73 });
74 }
75 ui.add_space(theme::space::MD);
76 }
77
78 // Import errors: files that failed before entering the store
79 // (informational only — nothing to remediate from this screen). M-13.
80 if import_count > 0 {
81 ui.label(
82 egui::RichText::new(format!(
83 "{import_count} file{} failed to import",
84 if import_count == 1 { "" } else { "s" },
85 ))
86 .strong()
87 .color(theme::accent_red()),
88 );
89 ui.label(
90 egui::RichText::new(
91 "These files weren't imported. Re-running the import \
92 is the only way to retry \u{2014} duplicates will be skipped.",
93 )
94 .small()
95 .color(theme::text_muted()),
96 );
97 ui.add_space(theme::space::SM);
98
99 egui::ScrollArea::vertical()
100 .id_salt("import_errors")
101 .max_height(200.0)
102 .show(ui, |ui| {
103 for err in &state.import_file_errors {
104 ui.horizontal(|ui| {
105 ui.label(&err.path);
106 ui.label(
107 egui::RichText::new(&err.error)
108 .small()
109 .color(theme::text_secondary()),
110 );
111 });
112 }
113 });
114 ui.add_space(theme::space::MD);
115 }
116
117 ui.add_space(theme::space::MD);
118 ui.horizontal(|ui| {
119 if widgets::primary_button(ui, "Keep All").clicked() {
120 state.dismiss_import_errors();
121 }
122 // Remove All Failed routes through the confirm dialog (C-2). The
123 // detail line surfaces the count so the user can see the blast
124 // radius before committing to permanent deletion.
125 if analysis_count > 0 && widgets::danger_button(ui, "Remove All Failed").clicked() {
126 state.pending_confirm = Some(ConfirmAction::RemoveFailedSamples {
127 single_index: None,
128 count: analysis_count,
129 name: None,
130 });
131 }
132 });
133 });
134 }
135