diff --git a/Readme.md b/Readme.md index ef74bb5..4af98ed 100644 --- a/Readme.md +++ b/Readme.md @@ -87,10 +87,12 @@ This will produce an executable file at `target/release/impala` that you can cop ### Known Networks -`a`: Enable/Disable auto-connect. +`t`: Enable/Disable auto-connect. `d`: Remove the network from the known networks list. +`a`: Show all the known networks. + ### Access Point `n`: Start a new access point. diff --git a/Release.md b/Release.md index ddc48df..e04e95a 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,7 @@ +## TBA + +- Show all the configured networks + ## 0.5.0 - 2025-11-21 - Support for WPA2 Entreprise diff --git a/src/config.rs b/src/config.rs index 8f148ab..8ab3331 100644 --- a/src/config.rs +++ b/src/config.rs @@ -93,13 +93,15 @@ pub struct KnownNetwork { #[serde(default = "default_station_remove_known_network")] pub remove: char, pub toggle_autoconnect: char, + pub show_all: char, } impl Default for KnownNetwork { fn default() -> Self { Self { remove: 'd', - toggle_autoconnect: 'a', + toggle_autoconnect: 't', + show_all: 'a', } } } diff --git a/src/handler.rs b/src/handler.rs index 277e3c7..07bafac 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -33,6 +33,11 @@ pub async fn toggle_connect(app: &mut App, sender: UnboundedSender) -> Re FocusedBlock::KnownNetworks => match &station.connected_network { Some(connected_net) => { if let Some(selected_net_index) = station.known_networks_state.selected() { + if selected_net_index > station.known_networks.len() - 1 { + // Can not connect to unavailble network + return Ok(()); + } + let (selected_net, _signal) = &station.known_networks[selected_net_index]; if selected_net.name == connected_net.name { @@ -55,6 +60,10 @@ pub async fn toggle_connect(app: &mut App, sender: UnboundedSender) -> Re } None => { if let Some(selected_net_index) = station.known_networks_state.selected() { + if selected_net_index > station.known_networks.len() - 1 { + // Can not connect to unavailble network + return Ok(()); + } let (selected_net, _signal) = &station.known_networks[selected_net_index]; let net_index = station .known_networks @@ -378,11 +387,20 @@ pub async fn handle_key_events( if let Some(net_index) = station.known_networks_state.selected() { - let (net, _signal) = - &station.known_networks[net_index]; - - if let Some(known_net) = &net.known_network { - known_net.forget(sender.clone()).await?; + if net_index > station.known_networks.len() - 1 { + let index = net_index.saturating_sub( + station.known_networks.len(), + ); + let network = + &station.unavailable_known_networks[index]; + network.forget(sender.clone()).await?; + } else { + let (net, _signal) = + &station.known_networks[net_index]; + + if let Some(known_net) = &net.known_network { + known_net.forget(sender.clone()).await?; + } } } } @@ -396,9 +414,9 @@ pub async fn handle_key_events( { if let Some(net_index) = station.known_networks_state.selected() + && net_index < station.known_networks.len() { - let (net, _signal) = - &station.known_networks[net_index]; + let (net, _) = &station.known_networks[net_index]; if let Some(known_net) = &net.known_network { known_net @@ -408,6 +426,14 @@ pub async fn handle_key_events( } } + // Show / Hide unavailable networks + KeyCode::Char(c) + if c == config.station.known_network.show_all => + { + station.show_unavailable_known_networks = + !station.show_unavailable_known_networks; + } + // Connect/Disconnect KeyCode::Enter => toggle_connect(app, sender).await?, KeyCode::Char(c) if c == config.station.toggle_connect => { @@ -420,12 +446,19 @@ pub async fn handle_key_events( let i = match station.known_networks_state.selected() { Some(i) => { - if i < station.known_networks.len() - 1 + let limit = if station + .show_unavailable_known_networks { - i + 1 + station.new_networks.len() + + station + .unavailable_known_networks + .len() + - 1 } else { - i - } + station.new_networks.len() - 1 + }; + + if i < limit { i + 1 } else { i } } None => 0, }; diff --git a/src/mode/station.rs b/src/mode/station.rs index fd3ee8e..ae4b0dc 100644 --- a/src/mode/station.rs +++ b/src/mode/station.rs @@ -25,6 +25,7 @@ use crate::{ config::Config, device::Device, event::Event, + mode::station::known_network::KnownNetwork, notification::{Notification, NotificationLevel}, }; @@ -38,9 +39,11 @@ pub struct Station { pub connected_network: Option, pub new_networks: Vec<(Network, i16)>, pub known_networks: Vec<(Network, i16)>, + pub unavailable_known_networks: Vec, pub known_networks_state: TableState, pub new_networks_state: TableState, pub diagnostic: Option, + pub show_unavailable_known_networks: bool, } impl Station { @@ -94,6 +97,24 @@ impl Station { .filter(|(net, _signal)| net.known_network.is_some()) .collect(); + let available_networks_names: Vec = + known_networks.iter().map(|(n, _)| n.name.clone()).collect(); + + let unavailable_known_networks = + if let Ok(iwd_known_networks) = session.known_networks().await { + let mut unavailable_known_networks = Vec::new(); + for iwd_network in iwd_known_networks { + if let Ok(known_network) = KnownNetwork::new(iwd_network).await + && !available_networks_names.contains(&known_network.name) + { + unavailable_known_networks.push(known_network); + } + } + unavailable_known_networks + } else { + Vec::new() + }; + let mut new_networks_state = TableState::default(); if new_networks.is_empty() { new_networks_state.select(None); @@ -122,9 +143,11 @@ impl Station { connected_network, new_networks, known_networks, + unavailable_known_networks, known_networks_state, new_networks_state, diagnostic, + show_unavailable_known_networks: false, }) } @@ -217,6 +240,29 @@ impl Station { self.known_networks = known_networks; } + let available_networks_names: Vec = self + .known_networks + .iter() + .map(|(n, _)| n.name.clone()) + .collect(); + + let unavailable_known_networks = + if let Ok(iwd_known_networks) = self.session.known_networks().await { + let mut unavailable_known_networks = Vec::new(); + for iwd_network in iwd_known_networks { + if let Ok(known_network) = KnownNetwork::new(iwd_network).await + && !available_networks_names.contains(&known_network.name) + { + unavailable_known_networks.push(known_network); + } + } + unavailable_known_networks + } else { + Vec::new() + }; + + self.unavailable_known_networks = unavailable_known_networks; + self.connected_network = connected_network; let iwd_station_diagnostic = self.session.stations_diagnostics().await.unwrap().pop(); @@ -403,7 +449,7 @@ impl Station { // // Known networks // - let rows: Vec = self + let mut rows: Vec = self .known_networks .iter() .map(|(net, signal)| { @@ -455,6 +501,22 @@ impl Station { }) .collect(); + if self.show_unavailable_known_networks { + self.unavailable_known_networks.iter().for_each(|net| { + let row = Row::new(vec![ + Line::from(""), + Line::from(net.name.clone()).centered(), + Line::from(net.network_type.to_string()).centered(), + Line::from(""), + Line::from(""), + Line::from(""), + ]) + .fg(Color::DarkGray); + + rows.push(row); + }); + } + let widths = [ Constraint::Length(2), Constraint::Length(25), @@ -644,7 +706,7 @@ impl Station { Span::from(" Nav"), ])], FocusedBlock::KnownNetworks => { - if frame.area().width <= 110 { + if frame.area().width <= 120 { vec![ Line::from(vec![ Span::from(if config.station.toggle_connect == ' ' { @@ -655,6 +717,9 @@ impl Station { .bold(), Span::from(" Dis/connect"), Span::from(" | "), + Span::from(config.station.known_network.show_all.to_string()).bold(), + Span::from(" Show All"), + Span::from(" | "), Span::from(config.station.known_network.remove.to_string()).bold(), Span::from(" Remove"), Span::from(" | "), @@ -695,6 +760,9 @@ impl Station { .bold(), Span::from(" Dis/connect"), Span::from(" | "), + Span::from(config.station.known_network.show_all.to_string()).bold(), + Span::from(" Show All"), + Span::from(" | "), Span::from(config.station.known_network.remove.to_string()).bold(), Span::from(" Remove"), Span::from(" | "), diff --git a/src/mode/station/known_network.rs b/src/mode/station/known_network.rs index 1f563de..74d7bf0 100644 --- a/src/mode/station/known_network.rs +++ b/src/mode/station/known_network.rs @@ -42,16 +42,20 @@ impl KnownNetwork { } pub async fn forget(&self, sender: UnboundedSender) -> Result<()> { - if let Err(e) = self.n.forget().await { - Notification::send(e.to_string(), NotificationLevel::Error, &sender.clone())?; - return Ok(()); + match self.n.forget().await { + Ok(()) => { + let _ = Notification::send( + format!("The Network {} is removed", self.name), + NotificationLevel::Info, + &sender, + ); + } + Err(e) => { + let _ = + Notification::send(e.to_string(), NotificationLevel::Error, &sender.clone()); + } } - Notification::send( - "Network Removed".to_string(), - NotificationLevel::Info, - &sender, - )?; Ok(()) }