use leptos::*; use shared::GlobalLimitRequest; fn format_bytes(bytes: i64) -> String { const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"]; if bytes < 1024 { return format!("{} B", bytes); } let i = (bytes as f64).log2().div_euclid(10.0) as usize; format!( "{:.1} {}", (bytes as f64) / 1024_f64.powi(i as i32), UNITS[i] ) } fn format_speed(bytes_per_sec: i64) -> String { if bytes_per_sec == 0 { return "0 B/s".to_string(); } format!("{}/s", format_bytes(bytes_per_sec)) } #[component] pub fn StatusBar() -> impl IntoView { let store = use_context::().expect("store not provided"); let stats = store.global_stats; let initial_theme = if let Some(win) = web_sys::window() { if let Some(doc) = win.document() { doc.document_element() .and_then(|el| el.get_attribute("data-theme")) .unwrap_or_else(|| "dark".to_string()) } else { "dark".to_string() } } else { "dark".to_string() }; let (current_theme, set_current_theme) = create_signal(initial_theme); create_effect(move |_| { if let Some(win) = web_sys::window() { if let Some(storage) = win.local_storage().ok().flatten() { if let Ok(Some(stored_theme)) = storage.get_item("vibetorrent_theme") { let theme = stored_theme.to_lowercase(); set_current_theme.set(theme.clone()); if let Some(doc) = win.document() { let _ = doc .document_element() .unwrap() .set_attribute("data-theme", &theme); } } } } }); // Preset limits in bytes/s let limits: Vec<(i64, &str)> = vec![ (0, "Unlimited"), (100 * 1024, "100 KB/s"), (500 * 1024, "500 KB/s"), (1024 * 1024, "1 MB/s"), (2 * 1024 * 1024, "2 MB/s"), (5 * 1024 * 1024, "5 MB/s"), (10 * 1024 * 1024, "10 MB/s"), (20 * 1024 * 1024, "20 MB/s"), ]; let set_limit = move |limit_type: &str, val: i64| { let limit_type = limit_type.to_string(); logging::log!("Setting {} limit to {}", limit_type, val); spawn_local(async move { let req_body = if limit_type == "down" { GlobalLimitRequest { max_download_rate: Some(val), max_upload_rate: None, } } else { GlobalLimitRequest { max_download_rate: None, max_upload_rate: Some(val), } }; let client = gloo_net::http::Request::post("/api/settings/global-limits").json(&req_body); match client { Ok(req) => match req.send().await { Ok(resp) => { if !resp.ok() { logging::error!( "Failed to set limit: {} {}", resp.status(), resp.status_text() ); } else { logging::log!("Limit set successfully"); } } Err(e) => logging::error!("Network error setting limit: {}", e), }, Err(e) => logging::error!("Failed to create request: {}", e), } }); }; // Signal-based dropdown state: 0=none, 1=download, 2=upload, 3=theme let (active_dropdown, set_active_dropdown) = create_signal(0u8); // Toggle a specific dropdown let toggle = move |id: u8| { let current = active_dropdown.get_untracked(); if current == id { set_active_dropdown.set(0); } else { set_active_dropdown.set(id); } }; // Close all dropdowns let close_all = move || { set_active_dropdown.set(0); }; view! { // Transparent overlay to close dropdowns when clicking outside
// --- DOWNLOAD SPEED DROPDOWN ---
{move || format_speed(stats.get().down_rate)} 0 } fallback=|| ()> {move || format!("(Limit: {})", format_speed(stats.get().down_limit.unwrap_or(0)))}
// --- UPLOAD SPEED DROPDOWN ---
{move || format_speed(stats.get().up_rate)} 0 } fallback=|| ()> {move || format!("(Limit: {})", format_speed(stats.get().up_limit.unwrap_or(0)))}
} }