Skip to main content

max / audiofiles

2.6 KB · 63 lines History Blame Raw
1 //! Blob-layout migration strip: a thin, cancellable progress row above the footer.
2 //!
3 //! Shown only while the background migration is relocating blobs from the legacy
4 //! flat store root into hash-prefix shards. Deliberately a strip and not a modal or
5 //! a full-screen mode: the migration auto-starts at vault open rather than being
6 //! asked for, and the library stays completely usable while it runs, because reads
7 //! resolve both layouts. Seizing the window for it would be the wrong trade.
8 //!
9 //! Cancelling is honest here. The sweep is resumable and records nothing until a
10 //! pass verifies the root is clean, so stopping defers the remainder to the next
11 //! open instead of abandoning or half-applying it.
12
13 use egui;
14
15 use super::theme;
16 use crate::state::BrowserState;
17
18 /// Draw the migration strip. No-op when no migration is running.
19 pub fn draw_layout_strip(ui: &mut egui::Ui, state: &mut BrowserState) {
20 let Some(progress) = state.layout_migration else {
21 return;
22 };
23
24 ui.add_space(theme::space::hair());
25 ui.horizontal(|ui| {
26 ui.label(
27 egui::RichText::new("Optimising storage layout")
28 .small()
29 .color(theme::content_secondary()),
30 );
31 ui.label(
32 egui::RichText::new(format!("{} / {} files", progress.completed, progress.total))
33 .small()
34 .color(theme::content_muted()),
35 );
36
37 // The button is laid out first from the right so the bar takes the
38 // remaining width instead of pushing the button off the row.
39 ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
40 if ui
41 .small_button("Pause")
42 .on_hover_text("Stop for now. Resumes the next time this vault opens.")
43 .clicked()
44 {
45 if let Err(e) = state.backend.cancel_layout_migration() {
46 tracing::warn!("failed to cancel layout migration: {e}");
47 }
48 // Clear the strip immediately rather than waiting for the
49 // worker's terminal event: the click has to feel like it did
50 // something, and the Complete event that follows sets the status
51 // line and would clear this anyway.
52 state.layout_migration = None;
53 }
54 ui.add(
55 egui::ProgressBar::new(progress.fraction())
56 .desired_height(theme::space::peer())
57 .show_percentage(),
58 );
59 });
60 });
61 ui.add_space(theme::space::hair());
62 }
63