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
140 changes: 47 additions & 93 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::config::Config;
use crate::device::Device;
use crate::event::Event;
use crate::mode::ap::APFocusedSection;
use crate::mode::station::KnownNetworkSelection;
use crate::mode::station::share::Share;
use crate::mode::station::speed_test::SpeedTest;
use crate::nm::{Mode, SecurityType};
Expand Down Expand Up @@ -65,57 +66,30 @@ pub async fn toggle_connect(app: &mut App, sender: UnboundedSender<Event>) -> 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 {
FocusedBlock::KnownNetworks => {
if let Some(KnownNetworkSelection::Network(data_index)) =
station.resolve_known_selection()
{
let (selected_net, _) = &station.known_networks[data_index];

let is_connected = station
.connected_network
.as_ref()
.is_some_and(|c| c.name == selected_net.name);

if is_connected {
station.disconnect(sender.clone()).await?;
} else {
let (net, _) = station.known_networks[data_index].clone();
if station.connected_network.is_some() {
station.disconnect(sender.clone()).await?;
} else {
let net_index = station
.known_networks
.iter()
.position(|(n, _s)| n.name == selected_net.name);

if let Some(index) = net_index {
let (net, _) = station.known_networks[index].clone();
station.disconnect(sender.clone()).await?;
tokio::spawn(async move {
// Known networks already have saved credentials
let _ = net.connect(sender.clone(), None).await;
});
}
}
}
}
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
.iter()
.position(|(n, _s)| n.name == selected_net.name);

if let Some(index) = net_index {
let (net, _) = station.known_networks[index].clone();
tokio::spawn(async move {
// Known networks already have saved credentials
let _ = net.connect(sender.clone(), None).await;
});
}
tokio::spawn(async move {
let _ = net.connect(sender.clone(), None).await;
});
}
}
},
}
_ => {}
}
}
Expand Down Expand Up @@ -561,16 +535,10 @@ pub async fn handle_key_events(
KeyCode::Char(c)
if c == config.station.known_network.share =>
{
if let Some(net_index) =
station.known_networks_state.selected()
{
if net_index > station.known_networks.len() - 1 {
let index = net_index.saturating_sub(
station.known_networks.len(),
);
match station.resolve_known_selection() {
Some(KnownNetworkSelection::Unavailable(index)) => {
let network =
&station.unavailable_known_networks[index];
// Check if it's a PSK network (WPA/WPA2/WPA3)
if matches!(
network.network_type,
SecurityType::WPA
Expand All @@ -587,10 +555,12 @@ pub async fn handle_key_events(
app.focused_block =
FocusedBlock::ShareNetwork;
}
} else {
}
Some(KnownNetworkSelection::Network(
data_index,
)) => {
let (network, _) =
&station.known_networks[net_index];
// Check if it's a PSK network (WPA/WPA2/WPA3)
&station.known_networks[data_index];
if matches!(
network.network_type,
SecurityType::WPA
Expand All @@ -609,30 +579,29 @@ pub async fn handle_key_events(
FocusedBlock::ShareNetwork;
}
}
_ => {}
}
}
// Remove a known network
KeyCode::Char(c)
if c == config.station.known_network.remove =>
{
if let Some(net_index) =
station.known_networks_state.selected()
{
if net_index > station.known_networks.len() - 1 {
let index = net_index.saturating_sub(
station.known_networks.len(),
);
match station.resolve_known_selection() {
Some(KnownNetworkSelection::Unavailable(index)) => {
let network =
&station.unavailable_known_networks[index];
network.forget(sender.clone()).await?;
} else {
let (net, _signal) =
&station.known_networks[net_index];

}
Some(KnownNetworkSelection::Network(
data_index,
)) => {
let (net, _) =
&station.known_networks[data_index];
if let Some(known_net) = &net.known_network {
known_net.forget(sender.clone()).await?;
}
}
_ => {}
}
}

Expand All @@ -643,13 +612,12 @@ pub async fn handle_key_events(
.known_network
.toggle_autoconnect =>
{
if let Some(net_index) =
station.known_networks_state.selected()
&& net_index < station.known_networks.len()
if let Some(KnownNetworkSelection::Network(
data_index,
)) = station.resolve_known_selection()
{
let (net, _) =
&mut station.known_networks[net_index];

&mut station.known_networks[data_index];
if let Some(known_net) = &mut net.known_network {
known_net
.toggle_autoconnect(sender.clone())
Expand Down Expand Up @@ -702,38 +670,24 @@ pub async fn handle_key_events(

// Scroll down
KeyCode::Char('j') | KeyCode::Down => {
if !station.known_networks.is_empty() {
let total = station.known_networks_total_rows();
if total > 0 {
let i =
match station.known_networks_state.selected() {
Some(i) => {
let limit = if station
.show_unavailable_known_networks
{
station.known_networks.len()
+ station
.unavailable_known_networks
.len()
- 1
} else {
station.known_networks.len() - 1
};

if i < limit { i + 1 } else { i }
}
Some(i) => (i + 1).min(total - 1),
None => 0,
};

station.known_networks_state.select(Some(i));
}
}
KeyCode::Char('k') | KeyCode::Up => {
if !station.known_networks.is_empty() {
let total = station.known_networks_total_rows();
if total > 0 {
let i =
match station.known_networks_state.selected() {
Some(i) => i.saturating_sub(1),
None => 0,
};

station.known_networks_state.select(Some(i));
}
}
Expand Down
45 changes: 45 additions & 0 deletions src/mode/station.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ use crate::{

use network::Network;

/// Result of resolving the selected known networks table index,
/// accounting for the ethernet row offset.
pub enum KnownNetworkSelection {
/// The ethernet row is selected (no-op for most actions)
Ethernet,
/// A known (visible) network at the given data index
Network(usize),
/// An unavailable (saved but not visible) network at the given index
Unavailable(usize),
}

/// Hidden network representation for NetworkManager
#[derive(Debug, Clone)]
pub struct HiddenNetwork {
Expand Down Expand Up @@ -366,6 +377,40 @@ impl Station {
Ok(())
}

/// Resolve the currently selected known networks table index to a typed selection,
/// accounting for the ethernet row offset and unavailable networks.
pub fn resolve_known_selection(&self) -> Option<KnownNetworkSelection> {
let selected = self.known_networks_state.selected()?;
let ethernet_offset = usize::from(self.is_ethernet_connected);

if selected < ethernet_offset {
return Some(KnownNetworkSelection::Ethernet);
}

let data_index = selected - ethernet_offset;
if data_index < self.known_networks.len() {
Some(KnownNetworkSelection::Network(data_index))
} else {
let unavail_index = data_index - self.known_networks.len();
if unavail_index < self.unavailable_known_networks.len() {
Some(KnownNetworkSelection::Unavailable(unavail_index))
} else {
None
}
}
}

/// Total number of rows in the known networks table (ethernet + known + unavailable).
pub fn known_networks_total_rows(&self) -> usize {
let ethernet_offset = usize::from(self.is_ethernet_connected);
let unavail = if self.show_unavailable_known_networks {
self.unavailable_known_networks.len()
} else {
0
};
ethernet_offset + self.known_networks.len() + unavail
}

pub fn render(
&mut self,
frame: &mut Frame,
Expand Down