diff --git a/client-gui/src/gui_app.rs b/client-gui/src/gui_app.rs index ae916af..7c5faf4 100644 --- a/client-gui/src/gui_app.rs +++ b/client-gui/src/gui_app.rs @@ -5,8 +5,9 @@ use client_network::{ }; use crossbeam_channel::{Receiver, Sender}; use egui::{ - Align, CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Layout, Response, - ScrollArea, SidePanel, Stroke, TopBottomPanel, Ui, ViewportCommand, + Align, CentralPanel, CollapsingHeader, Color32, Context, CornerRadius, Frame, Layout, + ProgressBar, Response, ScrollArea, SidePanel, Stroke, TopBottomPanel, Ui, Vec2, + ViewportCommand, }; use std::collections::HashSet; use std::{collections::HashMap, fmt::format, io::Seek}; @@ -54,6 +55,13 @@ pub struct P2PClientApp { current_downloading_file_map: MerkleTree, remaining_chunks: HashSet<[u8; 32]>, + + // total number of chunks expected for the current download (set when download starts) + current_total_chunks: Option, + + // number of chunks received so far (count of removed remaining_chunks) + current_received_chunks: usize, + root_downloading_file: String, } @@ -87,6 +95,8 @@ impl P2PClientApp { active_server: "".to_string(), shared_tree: generate_base_tree(), current_downloading_file_map: current_downloading_file_map, + current_total_chunks: None, + current_received_chunks: 0, root_downloading_file: "".to_string(), remaining_chunks: HashSet::new(), } @@ -103,6 +113,14 @@ impl P2PClientApp { pub fn clear_success(&mut self) { self.success_message = None; } + + fn set_current_total_chunks(&mut self, len: Option) { + self.current_total_chunks = len + } + + fn set_current_received_chunks(&mut self, arg: usize) { + self.current_received_chunks = arg + } } // --- eframe::App Trait Implementation --- @@ -291,6 +309,7 @@ impl eframe::App for P2PClientApp { true, )); self.remaining_chunks.insert(entry); + self.set_current_total_chunks(Some(self.remaining_chunks.len())); } self.remaining_chunks.remove(&hash); } @@ -299,6 +318,13 @@ impl eframe::App for P2PClientApp { } _ => {} } + + if let Some(total) = self.current_total_chunks { + // recompute received (safer than incrementing) + let received = total.saturating_sub(self.remaining_chunks.len()); + self.current_received_chunks = received; + } + if self.remaining_chunks.is_empty() { /*let file = OpenOptions::new() .append(true) @@ -323,6 +349,8 @@ impl eframe::App for P2PClientApp { } } }*/ + self.current_total_chunks = None; + self.current_received_chunks = 0; println!("bigfile téléchargé"); } } @@ -403,26 +431,35 @@ impl eframe::App for P2PClientApp { TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { ui.horizontal(|ui| { match self.server_status { - ServerStatus::Loading => { - ui.spinner(); - } - ServerStatus::Connected => { - ui.label("Registered but no server peer chosen..."); - } - ServerStatus::NotConnected => { - ui.label("No connection.."); - } - ServerStatus::ConnectedHandshake => { - let str = format!("📡"); - ui.label(str); - } + ServerStatus::Loading => ui.spinner(), + ServerStatus::Connected => ui.label("Registered but no server peer chosen..."), + ServerStatus::NotConnected => ui.label("No connection.."), + ServerStatus::ConnectedHandshake => ui.label("📡"), + }; + + ui.add_space(8.0); // small gap + + // desired progress bar width + let bar_width = 220.0f32; + // push it to the right by adding space equal to remaining width minus bar width + let push = (ui.available_width() - bar_width).max(0.0); + ui.add_space(push); + + if let Some(total) = self.current_total_chunks { + let received = self.current_received_chunks; + let frac = if total == 0 { + 1.0 + } else { + received as f32 / total as f32 + }; + + ui.add( + ProgressBar::new(frac) + .show_percentage() + .animate(true) + .desired_height(10.0), + ); } - ui.add_space(ui.available_width() - 30.0); - // formater mm:ss - let secs = self.remaining.as_secs(); - let minutes = secs / 60; - let seconds = secs % 60; - ui.label(format!("{:02}:{:02}", minutes, seconds)); }); }); @@ -685,7 +722,7 @@ impl eframe::App for P2PClientApp { ui.separator(); if let Some(active_peer) = &self.active_peer { - if let Some(tree) = self.loaded_fs.get(active_peer) { + if let Some(tree) = self.loaded_fs.clone().get(active_peer) { ScrollArea::vertical().show(ui, |ui| { // Start drawing the tree from the root hash self.draw_file_tree(ui, tree); @@ -745,7 +782,7 @@ impl eframe::App for P2PClientApp { // --- Helper for Drawing the Recursive File Tree --- impl P2PClientApp { - fn draw_file_tree(&self, ui: &mut Ui, tree: &MerkleTree) { + fn draw_file_tree(&mut self, ui: &mut Ui, tree: &MerkleTree) { assert!(self.active_peer.is_some()); assert!( self.loaded_fs @@ -762,7 +799,7 @@ impl P2PClientApp { } fn draw_file_node( - &self, + &mut self, ui: &mut Ui, to_draw: NodeHash, tree: &MerkleTree,