Skip to content
Merged
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
115 changes: 78 additions & 37 deletions nmrs-ui/src/ui/header.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -9,6 +11,7 @@ pub fn build_header(
list_container: &GtkBox,
parent_window: &gtk::ApplicationWindow,
stack: &gtk::Stack,
is_scanning: Rc<Cell<bool>>,
) -> HeaderBar {
let header = HeaderBar::new();
header.set_show_title_buttons(false);
Expand Down Expand Up @@ -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");
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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");
}
Expand All @@ -128,6 +119,56 @@ pub fn build_header(
header
}

async fn refresh_networks(
nm: &NetworkManager,
list_container: &GtkBox,
status: &Label,
pw: &gtk::ApplicationWindow,
stack: &gtk::Stack,
is_scanning: &Rc<Cell<bool>>,
) {
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: &gtk::Box) {
let mut child = container.first_child();
while let Some(widget) = child {
Expand Down
6 changes: 4 additions & 2 deletions nmrs-ui/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand Down