Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion mutant-web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ crate-type = ["cdylib", "rlib"]

wasm-bindgen = "0.2.95"
wasm-bindgen-futures = "0.4.45"
js-sys = "0.3.64"
js-sys = "0.3.72"
serde_cbor = "0.11.2"
serde = { version = "1.0.214", features = ["derive"] }
serde-wasm-bindgen = "0.6.5"
Expand Down Expand Up @@ -52,6 +52,7 @@ mime_guess = "2.0.4"
base64 = "0.21.7"
egui_extras = { version = "0.31.0", features = ["syntect"] }
uuid = { version = "1.17.0", features = ["v4"] }
gloo-timers = { version = "0.3.0", features = ["futures"] }

[dependencies.web-sys]
version = "0.3"
Expand Down Expand Up @@ -80,6 +81,7 @@ features = [
"HtmlMediaElement",
"HtmlSourceElement",
"Url",
"Response",
]


Expand Down
126 changes: 125 additions & 1 deletion mutant-web/src/app/components/progress.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use eframe::egui::{self, text::LayoutJob, ProgressBar};
use eframe::egui::{self, text::LayoutJob, ProgressBar, RichText};
use crate::app::theme::MutantColors;

pub fn progress(completion: f32, duration: String) -> ProgressBar {
let mut text = format!("{:.1}% - {}", completion * 100.0, duration);
Expand Down Expand Up @@ -44,3 +45,126 @@ pub fn detailed_progress(completion: f32, current: usize, total: usize, duration

ProgressBar::new(completion as f32).animate(true).text(job)
}

/// Modern styled progress bar for file transfers (Phase 1: Browser → Daemon)
pub fn file_transfer_progress(ui: &mut egui::Ui, completion: f32, bytes_transferred: u64, total_bytes: u64, filename: &str) {
egui::Frame::new()
.fill(MutantColors::SURFACE)
.stroke(egui::Stroke::new(1.0, MutantColors::BORDER_MEDIUM))
.inner_margin(egui::Margin::same(8))
.show(ui, |ui| {
ui.horizontal(|ui| {
// File icon
ui.label(RichText::new("📁").size(16.0).color(MutantColors::ACCENT_BLUE));

ui.vertical(|ui| {
// Filename
ui.label(RichText::new(filename).size(13.0).color(MutantColors::TEXT_PRIMARY));

// Progress bar
let progress_bar = ProgressBar::new(completion)
.fill(MutantColors::ACCENT_BLUE)
.animate(true);
Comment on lines +65 to +67
Copy link

Copilot AI Jun 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider reusing the existing styled_progress_bar utility to construct the progress bar for consistency across components, unless the deviation is intentional.

Suggested change
let progress_bar = ProgressBar::new(completion)
.fill(MutantColors::ACCENT_BLUE)
.animate(true);
let progress_bar = styled_progress_bar(completion, None, Some(MutantColors::ACCENT_BLUE));

Copilot uses AI. Check for mistakes.
ui.add(progress_bar);

// Transfer stats
let transferred_str = format_bytes(bytes_transferred);
let total_str = format_bytes(total_bytes);
let percentage = (completion * 100.0) as u32;

ui.label(RichText::new(format!("{} / {} ({}%)", transferred_str, total_str, percentage))
.size(11.0)
.color(MutantColors::TEXT_SECONDARY));
});
});
});
}

/// Modern styled progress bar for network uploads (Phase 2: Daemon → Network)
pub fn network_upload_progress(
ui: &mut egui::Ui,
reservation_progress: f32, reserved_count: usize,
upload_progress: f32, uploaded_count: usize,
confirmation_progress: f32, confirmed_count: usize,
total_chunks: usize,
elapsed_time: String
) {
egui::Frame::new()
.fill(MutantColors::SURFACE)
.stroke(egui::Stroke::new(1.0, MutantColors::BORDER_MEDIUM))
.inner_margin(egui::Margin::same(12))
.show(ui, |ui| {
ui.vertical(|ui| {
// Header
ui.horizontal(|ui| {
ui.label(RichText::new("🌐").size(16.0).color(MutantColors::ACCENT_ORANGE));
ui.label(RichText::new("Uploading to Autonomi Network")
.size(14.0)
.strong()
.color(MutantColors::TEXT_PRIMARY));
});

ui.add_space(8.0);

// Reservation phase
ui.horizontal(|ui| {
ui.label(RichText::new("Reserving:").size(12.0).color(MutantColors::TEXT_SECONDARY));
ui.add(ProgressBar::new(reservation_progress)
.fill(MutantColors::WARNING)
.animate(true));
ui.label(RichText::new(format!("{}/{}", reserved_count, total_chunks))
.size(11.0)
.color(MutantColors::TEXT_MUTED));
});

ui.add_space(4.0);

// Upload phase
ui.horizontal(|ui| {
ui.label(RichText::new("Uploading:").size(12.0).color(MutantColors::TEXT_SECONDARY));
ui.add(ProgressBar::new(upload_progress)
.fill(MutantColors::ACCENT_ORANGE)
.animate(true));
ui.label(RichText::new(format!("{}/{}", uploaded_count, total_chunks))
.size(11.0)
.color(MutantColors::TEXT_MUTED));
});

ui.add_space(4.0);

// Confirmation phase
ui.horizontal(|ui| {
ui.label(RichText::new("Confirming:").size(12.0).color(MutantColors::TEXT_SECONDARY));
ui.add(ProgressBar::new(confirmation_progress)
.fill(MutantColors::SUCCESS)
.animate(true));
ui.label(RichText::new(format!("{}/{}", confirmed_count, total_chunks))
.size(11.0)
.color(MutantColors::TEXT_MUTED));
});

ui.add_space(6.0);

// Elapsed time
ui.horizontal(|ui| {
ui.label(RichText::new("⏱").size(12.0).color(MutantColors::ACCENT_CYAN));
ui.label(RichText::new(format!("Elapsed: {}", elapsed_time))
.size(11.0)
.color(MutantColors::TEXT_MUTED));
});
});
});
}

/// Helper function to format bytes in human-readable format
fn format_bytes(bytes: u64) -> String {
if bytes >= 1024 * 1024 * 1024 {
format!("{:.1} GB", bytes as f64 / (1024.0 * 1024.0 * 1024.0))
} else if bytes >= 1024 * 1024 {
format!("{:.1} MB", bytes as f64 / (1024.0 * 1024.0))
} else if bytes >= 1024 {
format!("{:.1} KB", bytes as f64 / 1024.0)
} else {
format!("{} B", bytes)
}
}
Loading