From 14378cca52fe4f8fc104f2f65540e091e677df46 Mon Sep 17 00:00:00 2001 From: Akrm Al-Hakimi Date: Mon, 10 Nov 2025 12:52:54 -0500 Subject: [PATCH] fix: `refresh_networks` helper for proper scanning; adjusted polling to accurately display networks on launch --- nmrs-ui/src/ui/header.rs | 115 ++++++++++++++++++++++++++------------- nmrs-ui/src/ui/mod.rs | 6 +- 2 files changed, 82 insertions(+), 39 deletions(-) diff --git a/nmrs-ui/src/ui/header.rs b/nmrs-ui/src/ui/header.rs index 999ebe1b..cfb64e94 100644 --- a/nmrs-ui/src/ui/header.rs +++ b/nmrs-ui/src/ui/header.rs @@ -1,6 +1,8 @@ use gtk::prelude::*; use gtk::{Box as GtkBox, HeaderBar, Label, ListBox, Orientation, Switch}; use nmrs_core::NetworkManager; +use std::cell::Cell; +use std::rc::Rc; use crate::ui::networks; @@ -9,6 +11,7 @@ pub fn build_header( list_container: &GtkBox, parent_window: >k::ApplicationWindow, stack: >k::Stack, + is_scanning: Rc>, ) -> HeaderBar { let header = HeaderBar::new(); header.set_show_title_buttons(false); @@ -38,6 +41,7 @@ pub fn build_header( let wifi_switch_clone = wifi_switch.clone(); let pw = parent_window.clone(); let stack_clone = stack.clone(); + let is_scanning_clone = is_scanning.clone(); glib::MainContext::default().spawn_local(async move { stack_clone.set_visible_child_name("loading"); @@ -47,32 +51,26 @@ pub fn build_header( Ok(nm) => match nm.wifi_enabled().await { Ok(enabled) => { wifi_switch_clone.set_active(enabled); - if enabled { - status_clone.set_text("Scanning..."); - let _ = nm.scan_networks().await; - glib::timeout_future_seconds(2).await; - match nm.list_networks().await { - Ok(nets) => { - status_clone.set_text(""); - let list: ListBox = - networks::networks_view(&nets, &pw, &stack_clone); - list_container_clone.append(&list); - stack_clone.set_visible_child_name("networks"); - } - Err(err) => { - status_clone - .set_text(&format!("Error fetching networks: {err}")); - } - } + refresh_networks( + &nm, + &list_container_clone, + &status_clone, + &pw, + &stack_clone, + &is_scanning_clone, + ) + .await; } } - Err(err) => status_clone.set_text(&format!("Error: {err}")), + Err(err) => { + status_clone.set_text(&format!("Error fetching networks: {err}")); + } }, Err(err) => status_clone.set_text(&format!("Error: {err}")), } - }); - } + }) + }; { let pw2 = parent_window.clone(); @@ -84,6 +82,7 @@ pub fn build_header( let status_clone = status.clone(); let sw = sw.clone(); let stack_inner = stack_clone.clone(); + let is_scanning_clone = is_scanning.clone(); glib::MainContext::default().spawn_local(async move { clear_children(&list_container_clone); @@ -97,23 +96,15 @@ pub fn build_header( if sw.is_active() { if nm.wait_for_wifi_ready().await.is_ok() { - let _ = nm.scan_networks().await; - status_clone.set_text("Scanning..."); - glib::timeout_future_seconds(2).await; - - match nm.list_networks().await { - Ok(nets) => { - status_clone.set_text(""); - let list: ListBox = - networks::networks_view(&nets, &pw, &stack_inner); - list_container_clone.append(&list); - stack_inner.set_visible_child_name("networks"); - } - Err(err) => { - status_clone - .set_text(&format!("Error fetching networks: {err}")); - } - } + refresh_networks( + &nm, + &list_container_clone, + &status_clone, + &pw, + &stack_inner, + &is_scanning_clone, + ) + .await; } else { status_clone.set_text("Wi-Fi failed to initialize"); } @@ -128,6 +119,56 @@ pub fn build_header( header } +async fn refresh_networks( + nm: &NetworkManager, + list_container: &GtkBox, + status: &Label, + pw: >k::ApplicationWindow, + stack: >k::Stack, + is_scanning: &Rc>, +) { + if is_scanning.get() { + status.set_text("Scan already in progress"); + return; + } + is_scanning.set(true); + + clear_children(list_container); + status.set_text("Scanning..."); + + if let Err(err) = nm.scan_networks().await { + status.set_text(&format!("Scan failed: {err}")); + is_scanning.set(false); + return; + } + + let mut last_len = 0; + for _ in 0..5 { + let nets = nm.list_networks().await.unwrap_or_default(); + if nets.len() == last_len && last_len > 0 { + break; + } + last_len = nets.len(); + glib::timeout_future_seconds(1).await; + } + + match nm.list_networks().await { + Ok(mut nets) => { + // deduplicate by BSSID + // (doing by SSID hides dual-band entries) + nets.sort_by(|a, b| b.strength.unwrap_or(0).cmp(&a.strength.unwrap_or(0))); + + status.set_text(""); + let list: ListBox = networks::networks_view(&nets, pw, stack); + list_container.append(&list); + stack.set_visible_child_name("networks"); + } + Err(err) => status.set_text(&format!("Error fetching networks: {err}")), + } + + is_scanning.set(false); +} + fn clear_children(container: >k::Box) { let mut child = container.first_child(); while let Some(widget) = child { diff --git a/nmrs-ui/src/ui/mod.rs b/nmrs-ui/src/ui/mod.rs index 0085e247..cac2cfc2 100644 --- a/nmrs-ui/src/ui/mod.rs +++ b/nmrs-ui/src/ui/mod.rs @@ -8,6 +8,8 @@ use gtk::{ Application, ApplicationWindow, Box as GtkBox, Label, Orientation, ScrolledWindow, Spinner, Stack, }; +use std::cell::Cell; +use std::rc::Rc; pub fn build_ui(app: &Application) { let win = ApplicationWindow::new(app); @@ -17,8 +19,8 @@ pub fn build_ui(app: &Application) { let vbox = GtkBox::new(Orientation::Vertical, 0); let status = Label::new(None); let list_container = GtkBox::new(Orientation::Vertical, 0); - let stack = Stack::new(); + let is_scanning = Rc::new(Cell::new(false)); let spinner = Spinner::new(); spinner.set_halign(gtk::Align::Center); @@ -33,7 +35,7 @@ pub fn build_ui(app: &Application) { stack.add_named(&list_container, Some("networks")); - let header = header::build_header(&status, &list_container, &win, &stack); + let header = header::build_header(&status, &list_container, &win, &stack, is_scanning); vbox.append(&header); let scroller = ScrolledWindow::new();