Added comparing hw_address everywhere
This commit is contained in:
parent
b743c724ff
commit
2198fa9b9a
5 changed files with 479 additions and 279 deletions
|
|
@ -34,9 +34,13 @@ use zbus::Connection;
|
|||
use crate::{
|
||||
config, fl,
|
||||
network_manager::{
|
||||
active_conns::active_conns_subscription, available_wifi::AccessPoint,
|
||||
current_networks::ActiveConnectionInfo, devices::devices_subscription,
|
||||
network_manager_subscription, wireless_enabled::wireless_enabled_subscription,
|
||||
active_conns::active_conns_subscription,
|
||||
available_wifi::AccessPoint,
|
||||
current_networks::ActiveConnectionInfo,
|
||||
devices::devices_subscription,
|
||||
hw_address::{self, HwAddress},
|
||||
network_manager_subscription,
|
||||
wireless_enabled::wireless_enabled_subscription,
|
||||
NetworkManagerEvent, NetworkManagerRequest, NetworkManagerState,
|
||||
},
|
||||
};
|
||||
|
|
@ -67,6 +71,17 @@ impl NewConnectionState {
|
|||
}
|
||||
.ssid
|
||||
}
|
||||
pub fn hw_address(&self) -> HwAddress {
|
||||
match self {
|
||||
Self::EnterPassword {
|
||||
access_point,
|
||||
password: _,
|
||||
} => access_point,
|
||||
Self::Waiting(ap) => ap,
|
||||
Self::Failure(ap) => ap,
|
||||
}
|
||||
.hw_address
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NewConnectionState> for AccessPoint {
|
||||
|
|
@ -100,6 +115,7 @@ struct CosmicNetworkApplet {
|
|||
toggle_wifi_ctr: u128,
|
||||
token_tx: Option<calloop::channel::Sender<TokenRequest>>,
|
||||
failed_known_ssids: HashSet<String>,
|
||||
hw_device_to_show: Option<HwAddress>,
|
||||
}
|
||||
|
||||
fn wifi_icon(strength: u8) -> &'static str {
|
||||
|
|
@ -201,12 +217,28 @@ impl CosmicNetworkApplet {
|
|||
timeline.start();
|
||||
}
|
||||
}
|
||||
fn view_window_return<'a>(&self, mut content: Column<'a, Message>) -> Element<'a, Message> {
|
||||
let Spacing {
|
||||
space_xxs, space_s, ..
|
||||
} = theme::active().cosmic().spacing;
|
||||
|
||||
content = content
|
||||
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]))
|
||||
.push(menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings));
|
||||
|
||||
self.core
|
||||
.applet
|
||||
.popup_container(content.padding([8, 0, 8, 0]))
|
||||
.max_width(400.)
|
||||
.max_height(800.)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Message {
|
||||
ActivateKnownWifi(String),
|
||||
Disconnect(String),
|
||||
ActivateKnownWifi(String, HwAddress),
|
||||
Disconnect(String, HwAddress),
|
||||
TogglePopup,
|
||||
CloseRequested(window::Id),
|
||||
ToggleAirplaneMode(bool),
|
||||
|
|
@ -220,7 +252,8 @@ pub(crate) enum Message {
|
|||
Frame(Instant),
|
||||
Token(TokenUpdate),
|
||||
OpenSettings,
|
||||
ResetFailedKnownSsid(String),
|
||||
ResetFailedKnownSsid(String, HwAddress),
|
||||
OpenHwDevice(Option<HwAddress>),
|
||||
// Errored(String),
|
||||
}
|
||||
|
||||
|
|
@ -316,15 +349,15 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
success,
|
||||
req,
|
||||
} => {
|
||||
if let NetworkManagerRequest::SelectAccessPoint(ssid) = &req {
|
||||
if let NetworkManagerRequest::SelectAccessPoint(ssid, hw_address) = &req {
|
||||
let conn_match = self
|
||||
.new_connection
|
||||
.as_ref()
|
||||
.map(|c| c.ssid() == ssid)
|
||||
.map(|c| c.ssid() == ssid && c.hw_address() == *hw_address)
|
||||
.unwrap_or_default();
|
||||
if conn_match && success {
|
||||
if let Some(s) =
|
||||
state.active_conns.iter_mut().find(|ap| &ap.name() == ssid)
|
||||
state.active_conns.iter_mut().find(|ap| &ap.name() == ssid && ap.hw_address() == *hw_address)
|
||||
{
|
||||
match s {
|
||||
ActiveConnectionInfo::WiFi { state, .. } => {
|
||||
|
|
@ -343,11 +376,11 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
{
|
||||
self.failed_known_ssids.insert(ssid.clone());
|
||||
}
|
||||
} else if let NetworkManagerRequest::Password(ssid, _) = &req {
|
||||
} else if let NetworkManagerRequest::Password(ssid, _, hw_address) = &req {
|
||||
if let Some(NewConnectionState::Waiting(access_point)) =
|
||||
self.new_connection.clone()
|
||||
{
|
||||
if !success && ssid == &access_point.ssid {
|
||||
if !success && ssid == &access_point.ssid && *hw_address == access_point.hw_address {
|
||||
self.new_connection =
|
||||
Some(NewConnectionState::Failure(access_point.clone()));
|
||||
} else {
|
||||
|
|
@ -358,7 +391,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
access_point, ..
|
||||
}) = self.new_connection.clone()
|
||||
{
|
||||
if success && ssid == &access_point.ssid {
|
||||
if success && ssid == &access_point.ssid && *hw_address == access_point.hw_address{
|
||||
self.new_connection = None;
|
||||
self.show_visible_networks = false;
|
||||
}
|
||||
|
|
@ -396,6 +429,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
|
||||
let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(
|
||||
access_point.ssid.clone(),
|
||||
access_point.hw_address.clone(),
|
||||
));
|
||||
|
||||
self.new_connection = Some(NewConnectionState::EnterPassword {
|
||||
|
|
@ -430,18 +464,19 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
let _ = tx.unbounded_send(NetworkManagerRequest::Password(
|
||||
access_point.ssid.clone(),
|
||||
password,
|
||||
access_point.hw_address,
|
||||
));
|
||||
self.new_connection
|
||||
.replace(NewConnectionState::Waiting(access_point));
|
||||
};
|
||||
}
|
||||
Message::ActivateKnownWifi(ssid) => {
|
||||
Message::ActivateKnownWifi(ssid, hw_address) => {
|
||||
let tx = if let Some(tx) = self.nm_sender.as_ref() {
|
||||
if let Some(ap) = self
|
||||
.nm_state
|
||||
.known_access_points
|
||||
.iter_mut()
|
||||
.find(|c| c.ssid == ssid)
|
||||
.find(|c| c.ssid == ssid && c.hw_address == hw_address)
|
||||
{
|
||||
ap.working = true;
|
||||
}
|
||||
|
|
@ -449,19 +484,20 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
} else {
|
||||
return Task::none();
|
||||
};
|
||||
let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(ssid));
|
||||
let _ =
|
||||
tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(ssid, hw_address));
|
||||
}
|
||||
Message::CancelNewConnection => {
|
||||
self.new_connection = None;
|
||||
}
|
||||
Message::Disconnect(ssid) => {
|
||||
Message::Disconnect(ssid, hw_address) => {
|
||||
self.new_connection = None;
|
||||
let tx = if let Some(tx) = self.nm_sender.as_ref() {
|
||||
if let Some(ActiveConnectionInfo::WiFi { state, .. }) = self
|
||||
.nm_state
|
||||
.active_conns
|
||||
.iter_mut()
|
||||
.find(|c| c.name() == ssid)
|
||||
.find(|c| c.name() == ssid && c.hw_address() == hw_address)
|
||||
{
|
||||
*state = ActiveConnectionState::Deactivating;
|
||||
}
|
||||
|
|
@ -472,6 +508,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
let _ = tx.unbounded_send(NetworkManagerRequest::Disconnect(ssid));
|
||||
}
|
||||
Message::CloseRequested(id) => {
|
||||
self.hw_device_to_show = None;
|
||||
if Some(id) == self.popup {
|
||||
self.popup = None;
|
||||
}
|
||||
|
|
@ -502,24 +539,27 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
tokio::spawn(cosmic::process::spawn(cmd));
|
||||
}
|
||||
},
|
||||
Message::ResetFailedKnownSsid(ssid) => {
|
||||
Message::OpenHwDevice(hw_address) => {
|
||||
self.hw_device_to_show = hw_address;
|
||||
}
|
||||
Message::ResetFailedKnownSsid(ssid, hw_address) => {
|
||||
let ap = if let Some(pos) = self
|
||||
.nm_state
|
||||
.known_access_points
|
||||
.iter()
|
||||
.position(|ap| ap.ssid == ssid)
|
||||
.position(|ap| ap.ssid == ssid && ap.hw_address == hw_address)
|
||||
{
|
||||
self.nm_state.known_access_points.remove(pos)
|
||||
} else if let Some((pos, ap)) = self
|
||||
.nm_state
|
||||
.active_conns
|
||||
.iter()
|
||||
.position(|conn| conn.name() == ssid)
|
||||
.position(|conn| conn.name() == ssid && conn.hw_address() == hw_address)
|
||||
.zip(
|
||||
self.nm_state
|
||||
.wireless_access_points
|
||||
.iter()
|
||||
.find(|ap| ap.ssid == ssid),
|
||||
.find(|ap| ap.ssid == ssid && ap.hw_address == hw_address),
|
||||
)
|
||||
{
|
||||
self.nm_state.active_conns.remove(pos);
|
||||
|
|
@ -556,6 +596,9 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
for conn in &self.nm_state.active_conns {
|
||||
match conn {
|
||||
ActiveConnectionInfo::Vpn { name, ip_addresses } => {
|
||||
if self.hw_device_to_show.is_some() {
|
||||
continue;
|
||||
}
|
||||
let mut ipv4 = Vec::with_capacity(ip_addresses.len() + 1);
|
||||
ipv4.push(text::body(name).into());
|
||||
for addr in ip_addresses {
|
||||
|
|
@ -583,10 +626,15 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
}
|
||||
ActiveConnectionInfo::Wired {
|
||||
name,
|
||||
hw_address: _,
|
||||
hw_address,
|
||||
speed,
|
||||
ip_addresses,
|
||||
} => {
|
||||
if self.hw_device_to_show.is_some()
|
||||
&& *hw_address != self.hw_device_to_show.unwrap()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let mut ipv4 = Vec::with_capacity(ip_addresses.len() + 1);
|
||||
ipv4.push(text::body(name).into());
|
||||
for addr in ip_addresses {
|
||||
|
|
@ -622,8 +670,13 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
ip_addresses,
|
||||
state,
|
||||
strength,
|
||||
..
|
||||
hw_address,
|
||||
} => {
|
||||
if self.hw_device_to_show.is_some()
|
||||
&& hw_address != self.hw_device_to_show.as_ref().unwrap()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let mut ipv4 = Vec::with_capacity(ip_addresses.len());
|
||||
for addr in ip_addresses {
|
||||
ipv4.push(text(format!("{}: {}", fl!("ipv4"), addr)).size(12).into());
|
||||
|
|
@ -660,7 +713,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
from_name("view-refresh-symbolic").size(16),
|
||||
)
|
||||
.icon_size(16)
|
||||
.on_press(Message::ResetFailedKnownSsid(name.clone()))
|
||||
.on_press(Message::ResetFailedKnownSsid(name.clone(), *hw_address))
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
|
@ -671,42 +724,65 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
.align_y(Alignment::Center)
|
||||
.spacing(8)
|
||||
)
|
||||
.on_press(Message::Disconnect(name.clone()))]
|
||||
.on_press(Message::Disconnect(name.clone(), *hw_address))]
|
||||
.align_x(Alignment::Center),
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut content = column![
|
||||
vpn_ethernet_col,
|
||||
padded_control(
|
||||
anim!(
|
||||
//toggler
|
||||
AIRPLANE_MODE,
|
||||
&self.timeline,
|
||||
fl!("airplane-mode"),
|
||||
self.nm_state.airplane_mode,
|
||||
|_chain, enable| { Message::ToggleAirplaneMode(enable) },
|
||||
)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
),
|
||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||
padded_control(
|
||||
anim!(
|
||||
//toggler
|
||||
WIFI,
|
||||
&self.timeline,
|
||||
fl!("wifi"),
|
||||
self.nm_state.wifi_enabled,
|
||||
|_chain, enable| { Message::ToggleWiFi(enable) },
|
||||
)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
),
|
||||
]
|
||||
.align_x(Alignment::Center);
|
||||
let mut content = if let Some(hw_device_to_show) = self.hw_device_to_show.as_ref() {
|
||||
column![
|
||||
vpn_ethernet_col,
|
||||
menu_button(row![
|
||||
container(
|
||||
icon::from_name("go-previous-symbolic")
|
||||
.size(16)
|
||||
.symbolic(true)
|
||||
)
|
||||
.align_x(Alignment::Start)
|
||||
.align_y(Alignment::Center)
|
||||
.width(Length::Fixed(24.0))
|
||||
.height(Length::Fixed(24.0)),
|
||||
text::body(hw_device_to_show.to_string())
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_y(Alignment::Center),
|
||||
])
|
||||
.on_press(Message::OpenHwDevice(None))
|
||||
]
|
||||
} else {
|
||||
column![
|
||||
vpn_ethernet_col,
|
||||
padded_control(
|
||||
anim!(
|
||||
//toggler
|
||||
AIRPLANE_MODE,
|
||||
&self.timeline,
|
||||
fl!("airplane-mode"),
|
||||
self.nm_state.airplane_mode,
|
||||
|_chain, enable| { Message::ToggleAirplaneMode(enable) },
|
||||
)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
),
|
||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||
padded_control(
|
||||
anim!(
|
||||
//toggler
|
||||
WIFI,
|
||||
&self.timeline,
|
||||
fl!("wifi"),
|
||||
self.nm_state.wifi_enabled,
|
||||
|_chain, enable| { Message::ToggleWiFi(enable) },
|
||||
)
|
||||
.text_size(14)
|
||||
.width(Length::Fill)
|
||||
),
|
||||
]
|
||||
.align_x(Alignment::Center)
|
||||
};
|
||||
|
||||
if self.nm_state.airplane_mode {
|
||||
content = content.push(
|
||||
column!(
|
||||
|
|
@ -722,237 +798,286 @@ impl cosmic::Application for CosmicNetworkApplet {
|
|||
.align_x(Alignment::Center)
|
||||
.width(Length::Fill),
|
||||
);
|
||||
} else {
|
||||
if self.nm_state.wifi_enabled {
|
||||
content = content.push(
|
||||
padded_control(divider::horizontal::default()).padding([space_xxs, space_s]),
|
||||
);
|
||||
for known in &self.nm_state.known_access_points {
|
||||
let mut btn_content = Vec::with_capacity(2);
|
||||
let ssid = text::body(&known.ssid).width(Length::Fill);
|
||||
if known.working {
|
||||
btn_content.push(
|
||||
icon::from_name("network-wireless-acquiring-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
btn_content.push(
|
||||
icon::from_name("process-working-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
} else if matches!(known.state, DeviceState::Unavailable) {
|
||||
btn_content.push(
|
||||
icon::from_name("network-wireless-disconnected-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
} else {
|
||||
btn_content.push(
|
||||
icon::from_name(wifi_icon(known.strength))
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
}
|
||||
return self.view_window_return(content);
|
||||
}
|
||||
|
||||
if self.failed_known_ssids.contains(&known.ssid) {
|
||||
btn_content.push(
|
||||
cosmic::widget::button::icon(
|
||||
from_name("view-refresh-symbolic").size(16),
|
||||
)
|
||||
.icon_size(16)
|
||||
.on_press(Message::ResetFailedKnownSsid(known.ssid.clone()))
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
if !self.nm_state.wifi_enabled {
|
||||
return self.view_window_return(content);
|
||||
}
|
||||
|
||||
let mut btn = menu_button(
|
||||
content = content
|
||||
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]));
|
||||
|
||||
let wireless_hw_devices = self
|
||||
.nm_state
|
||||
.wireless_access_points
|
||||
.iter()
|
||||
.map(|ap| ap.hw_address)
|
||||
.collect::<std::collections::BTreeSet<_>>();
|
||||
|
||||
if wireless_hw_devices.len() > 1 && self.hw_device_to_show.is_none() {
|
||||
for hw_device in wireless_hw_devices {
|
||||
let display_name = hw_device.to_string();
|
||||
|
||||
let btn_content = vec![
|
||||
column![
|
||||
text::body(display_name),
|
||||
Column::with_children(vec![text("Adapter").size(10).into()])
|
||||
]
|
||||
.width(Length::Fill)
|
||||
.into(),
|
||||
icon::from_name("go-next-symbolic")
|
||||
.size(16)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
];
|
||||
content = content.push(Element::from(
|
||||
column![menu_button(
|
||||
Row::with_children(btn_content)
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(8),
|
||||
);
|
||||
btn = match known.state {
|
||||
DeviceState::Failed
|
||||
| DeviceState::Unknown
|
||||
| DeviceState::Unmanaged
|
||||
| DeviceState::Disconnected
|
||||
| DeviceState::NeedAuth => {
|
||||
btn.on_press(Message::ActivateKnownWifi(known.ssid.clone()))
|
||||
}
|
||||
DeviceState::Activated => {
|
||||
btn.on_press(Message::Disconnect(known.ssid.clone()))
|
||||
}
|
||||
_ => btn,
|
||||
};
|
||||
known_wifi.push(Element::from(row![btn].align_y(Alignment::Center)));
|
||||
}
|
||||
|
||||
let has_known_wifi = !known_wifi.is_empty();
|
||||
content = content.push(Column::with_children(known_wifi));
|
||||
if has_known_wifi {
|
||||
content = content.push(
|
||||
padded_control(divider::horizontal::default())
|
||||
.padding([space_xxs, space_s]),
|
||||
);
|
||||
}
|
||||
|
||||
let dropdown_icon = if self.show_visible_networks {
|
||||
"go-up-symbolic"
|
||||
} else {
|
||||
"go-down-symbolic"
|
||||
};
|
||||
let available_connections_btn = menu_button(row![
|
||||
text::body(fl!("visible-wireless-networks"))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_y(Alignment::Center),
|
||||
container(icon::from_name(dropdown_icon).size(16).symbolic(true))
|
||||
.center(Length::Fixed(24.0))
|
||||
])
|
||||
.on_press(Message::ToggleVisibleNetworks);
|
||||
content = content.push(available_connections_btn);
|
||||
}
|
||||
}
|
||||
if self.show_visible_networks {
|
||||
if let Some(new_conn_state) = self.new_connection.as_ref() {
|
||||
match new_conn_state {
|
||||
NewConnectionState::EnterPassword {
|
||||
access_point,
|
||||
password,
|
||||
} => {
|
||||
let id = padded_control(
|
||||
row![
|
||||
icon::from_name("network-wireless-acquiring-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&access_point.ssid),
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(12),
|
||||
);
|
||||
content = content.push(id);
|
||||
let col = padded_control(
|
||||
column![
|
||||
text::body(fl!("enter-password")),
|
||||
text_input("", password)
|
||||
.on_input(Message::Password)
|
||||
.on_paste(Message::Password)
|
||||
.on_submit(Message::SubmitPassword)
|
||||
.password(),
|
||||
container(text::body(fl!("router-wps-button"))).padding(8),
|
||||
row![
|
||||
button::standard(fl!("cancel"))
|
||||
.on_press(Message::CancelNewConnection),
|
||||
button::suggested(fl!("connect"))
|
||||
.on_press(Message::SubmitPassword)
|
||||
]
|
||||
.spacing(24)
|
||||
]
|
||||
.spacing(8)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(col);
|
||||
}
|
||||
NewConnectionState::Waiting(access_point) => {
|
||||
let id = row![
|
||||
)
|
||||
.on_press(Message::OpenHwDevice(Some(hw_device.clone())))]
|
||||
.align_x(Alignment::Center),
|
||||
));
|
||||
}
|
||||
|
||||
return self.view_window_return(content);
|
||||
}
|
||||
|
||||
for known in &self.nm_state.known_access_points {
|
||||
if let Some(filter_hw_address) = self.hw_device_to_show.as_ref() {
|
||||
if filter_hw_address != &known.hw_address {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut btn_content = Vec::with_capacity(2);
|
||||
let ssid = text::body(&known.ssid).width(Length::Fill);
|
||||
if known.working {
|
||||
btn_content.push(
|
||||
icon::from_name("network-wireless-acquiring-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
btn_content.push(
|
||||
icon::from_name("process-working-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
} else if matches!(known.state, DeviceState::Unavailable) {
|
||||
btn_content.push(
|
||||
icon::from_name("network-wireless-disconnected-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
} else {
|
||||
btn_content.push(
|
||||
icon::from_name(wifi_icon(known.strength))
|
||||
.size(24)
|
||||
.symbolic(true)
|
||||
.into(),
|
||||
);
|
||||
btn_content.push(ssid.into());
|
||||
}
|
||||
|
||||
if self.failed_known_ssids.contains(&known.ssid) {
|
||||
btn_content.push(
|
||||
cosmic::widget::button::icon(from_name("view-refresh-symbolic").size(16))
|
||||
.icon_size(16)
|
||||
.on_press(Message::ResetFailedKnownSsid(
|
||||
known.ssid.clone(),
|
||||
known.hw_address,
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
let mut btn = menu_button(
|
||||
Row::with_children(btn_content)
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(8),
|
||||
);
|
||||
btn = match known.state {
|
||||
DeviceState::Failed
|
||||
| DeviceState::Unknown
|
||||
| DeviceState::Unmanaged
|
||||
| DeviceState::Disconnected
|
||||
| DeviceState::NeedAuth => btn.on_press(Message::ActivateKnownWifi(
|
||||
known.ssid.clone(),
|
||||
known.hw_address.clone(),
|
||||
)),
|
||||
DeviceState::Activated => {
|
||||
btn.on_press(Message::Disconnect(known.ssid.clone(), known.hw_address))
|
||||
}
|
||||
_ => btn,
|
||||
};
|
||||
known_wifi.push(Element::from(row![btn].align_y(Alignment::Center)));
|
||||
}
|
||||
let has_known_wifi = !known_wifi.is_empty();
|
||||
content = content.push(Column::with_children(known_wifi));
|
||||
if has_known_wifi {
|
||||
content = content
|
||||
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]));
|
||||
}
|
||||
|
||||
let dropdown_icon = if self.show_visible_networks {
|
||||
"go-up-symbolic"
|
||||
} else {
|
||||
"go-down-symbolic"
|
||||
};
|
||||
let available_connections_btn = menu_button(row![
|
||||
text::body(fl!("visible-wireless-networks"))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fixed(24.0))
|
||||
.align_y(Alignment::Center),
|
||||
container(icon::from_name(dropdown_icon).size(16).symbolic(true))
|
||||
.center(Length::Fixed(24.0))
|
||||
])
|
||||
.on_press(Message::ToggleVisibleNetworks);
|
||||
content = content.push(available_connections_btn);
|
||||
|
||||
if self.show_visible_networks {
|
||||
return self.view_window_return(content);
|
||||
}
|
||||
|
||||
if let Some(new_conn_state) = self.new_connection.as_ref() {
|
||||
match new_conn_state {
|
||||
NewConnectionState::EnterPassword {
|
||||
access_point,
|
||||
password,
|
||||
} => {
|
||||
let id = padded_control(
|
||||
row![
|
||||
icon::from_name("network-wireless-acquiring-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&access_point.ssid),
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.width(Length::Fill)
|
||||
.spacing(12);
|
||||
let connecting = padded_control(
|
||||
.spacing(12),
|
||||
);
|
||||
content = content.push(id);
|
||||
let col = padded_control(
|
||||
column![
|
||||
text::body(fl!("enter-password")),
|
||||
text_input("", password)
|
||||
.on_input(Message::Password)
|
||||
.on_paste(Message::Password)
|
||||
.on_submit(Message::SubmitPassword)
|
||||
.password(),
|
||||
container(text::body(fl!("router-wps-button"))).padding(8),
|
||||
row![
|
||||
id,
|
||||
icon::from_name("process-working-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
button::standard(fl!("cancel"))
|
||||
.on_press(Message::CancelNewConnection),
|
||||
button::suggested(fl!("connect")).on_press(Message::SubmitPassword)
|
||||
]
|
||||
.spacing(8),
|
||||
);
|
||||
content = content.push(connecting);
|
||||
}
|
||||
NewConnectionState::Failure(access_point) => {
|
||||
let id = padded_control(
|
||||
row![
|
||||
icon::from_name("network-wireless-error-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&access_point.ssid),
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(12),
|
||||
)
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(id);
|
||||
let col = padded_control(
|
||||
column![
|
||||
text(fl!("unable-to-connect")),
|
||||
text(fl!("check-wifi-connection")),
|
||||
row![
|
||||
button::standard(fl!("cancel"))
|
||||
.on_press(Message::CancelNewConnection),
|
||||
button::suggested(fl!("connect")).on_press(
|
||||
Message::SelectWirelessAccessPoint(access_point.clone())
|
||||
)
|
||||
]
|
||||
.spacing(24)
|
||||
]
|
||||
.spacing(16)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(col);
|
||||
}
|
||||
.spacing(24)
|
||||
]
|
||||
.spacing(8)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(col);
|
||||
}
|
||||
} else if self.nm_state.wifi_enabled {
|
||||
let mut list_col = Vec::with_capacity(self.nm_state.wireless_access_points.len());
|
||||
for ap in &self.nm_state.wireless_access_points {
|
||||
if self
|
||||
.nm_state
|
||||
.active_conns
|
||||
.iter()
|
||||
.any(|a| ap.ssid == a.name())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let button = menu_button(
|
||||
NewConnectionState::Waiting(access_point) => {
|
||||
let id = row![
|
||||
icon::from_name("network-wireless-acquiring-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&access_point.ssid),
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.width(Length::Fill)
|
||||
.spacing(12);
|
||||
let connecting = padded_control(
|
||||
row![
|
||||
icon::from_name(wifi_icon(ap.strength))
|
||||
.size(16)
|
||||
id,
|
||||
icon::from_name("process-working-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&ap.ssid).align_y(Alignment::Center)
|
||||
]
|
||||
.spacing(8),
|
||||
);
|
||||
content = content.push(connecting);
|
||||
}
|
||||
NewConnectionState::Failure(access_point) => {
|
||||
let id = padded_control(
|
||||
row![
|
||||
icon::from_name("network-wireless-error-symbolic")
|
||||
.size(24)
|
||||
.symbolic(true),
|
||||
text::body(&access_point.ssid),
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(12),
|
||||
)
|
||||
.on_press(Message::SelectWirelessAccessPoint(ap.clone()));
|
||||
list_col.push(button.into());
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(id);
|
||||
let col = padded_control(
|
||||
column![
|
||||
text(fl!("unable-to-connect")),
|
||||
text(fl!("check-wifi-connection")),
|
||||
row![
|
||||
button::standard(fl!("cancel"))
|
||||
.on_press(Message::CancelNewConnection),
|
||||
button::suggested(fl!("connect")).on_press(
|
||||
Message::SelectWirelessAccessPoint(access_point.clone())
|
||||
)
|
||||
]
|
||||
.spacing(24)
|
||||
]
|
||||
.spacing(16)
|
||||
.align_x(Alignment::Center),
|
||||
)
|
||||
.align_x(Alignment::Center);
|
||||
content = content.push(col);
|
||||
}
|
||||
content = content
|
||||
.push(scrollable(Column::with_children(list_col)).height(Length::Fixed(300.0)));
|
||||
}
|
||||
} else if self.nm_state.wifi_enabled {
|
||||
let mut list_col = Vec::with_capacity(self.nm_state.wireless_access_points.len());
|
||||
for ap in &self.nm_state.wireless_access_points {
|
||||
if ap.hw_address != self.hw_device_to_show.unwrap_or(ap.hw_address) {
|
||||
continue;
|
||||
}
|
||||
if self
|
||||
.nm_state
|
||||
.active_conns
|
||||
.iter()
|
||||
.any(|a| ap.ssid == a.name() && ap.hw_address == a.hw_address())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if self
|
||||
.nm_state
|
||||
.known_access_points
|
||||
.iter()
|
||||
.any(|a| ap.ssid == a.ssid && ap.hw_address == a.hw_address)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let button = menu_button(
|
||||
row![
|
||||
icon::from_name(wifi_icon(ap.strength))
|
||||
.size(16)
|
||||
.symbolic(true),
|
||||
text::body(&ap.ssid).align_y(Alignment::Center)
|
||||
]
|
||||
.align_y(Alignment::Center)
|
||||
.spacing(12),
|
||||
)
|
||||
.on_press(Message::SelectWirelessAccessPoint(ap.clone()));
|
||||
list_col.push(button.into());
|
||||
}
|
||||
content = content
|
||||
.push(scrollable(Column::with_children(list_col)).height(Length::Fixed(300.0)));
|
||||
}
|
||||
content = content
|
||||
.push(padded_control(divider::horizontal::default()).padding([space_xxs, space_s]))
|
||||
.push(menu_button(text::body(fl!("settings"))).on_press(Message::OpenSettings));
|
||||
|
||||
self.core
|
||||
.applet
|
||||
.popup_container(content.padding([8, 0, 8, 0]))
|
||||
.max_width(400.)
|
||||
.max_height(800.)
|
||||
.into()
|
||||
self.view_window_return(content)
|
||||
}
|
||||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use itertools::Itertools;
|
|||
use std::collections::HashMap;
|
||||
use zbus::zvariant::ObjectPath;
|
||||
|
||||
use super::hw_address::HwAddress;
|
||||
|
||||
pub async fn handle_wireless_device(
|
||||
device: WirelessDevice<'_>,
|
||||
hw_address: Option<String>,
|
||||
|
|
@ -45,7 +47,10 @@ pub async fn handle_wireless_device(
|
|||
state,
|
||||
working: false,
|
||||
path: ap.inner().path().to_owned(),
|
||||
hw_address: hw_address.as_ref().unwrap_or(&"".to_string()).clone(),
|
||||
hw_address: hw_address
|
||||
.as_ref()
|
||||
.and_then(|str_addr| HwAddress::from_str(str_addr))
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -63,5 +68,5 @@ pub struct AccessPoint {
|
|||
pub state: DeviceState,
|
||||
pub working: bool,
|
||||
pub path: ObjectPath<'static>,
|
||||
pub hw_address: String,
|
||||
pub hw_address: HwAddress,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use cosmic_dbus_networkmanager::{
|
|||
};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use super::hw_address::HwAddress;
|
||||
|
||||
pub async fn active_connections(
|
||||
active_connections: Vec<ActiveConnection<'_>>,
|
||||
) -> zbus::Result<Vec<ActiveConnectionInfo>> {
|
||||
|
|
@ -40,7 +42,8 @@ pub async fn active_connections(
|
|||
Some(SpecificDevice::Wired(wired_device)) => {
|
||||
info.push(ActiveConnectionInfo::Wired {
|
||||
name: connection.id().await?,
|
||||
hw_address: wired_device.hw_address().await?,
|
||||
hw_address: HwAddress::from_string(&wired_device.hw_address().await?)
|
||||
.unwrap_or_default(),
|
||||
speed: wired_device.speed().await?,
|
||||
ip_addresses: addresses.clone(),
|
||||
});
|
||||
|
|
@ -50,7 +53,10 @@ pub async fn active_connections(
|
|||
info.push(ActiveConnectionInfo::WiFi {
|
||||
name: String::from_utf8_lossy(&access_point.ssid().await?).into_owned(),
|
||||
ip_addresses: addresses.clone(),
|
||||
hw_address: wireless_device.hw_address().await?,
|
||||
hw_address: HwAddress::from_string(
|
||||
&wireless_device.hw_address().await?,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
state,
|
||||
strength: access_point.strength().await.unwrap_or_default(),
|
||||
});
|
||||
|
|
@ -83,14 +89,14 @@ pub async fn active_connections(
|
|||
pub enum ActiveConnectionInfo {
|
||||
Wired {
|
||||
name: String,
|
||||
hw_address: String,
|
||||
hw_address: HwAddress,
|
||||
speed: u32,
|
||||
ip_addresses: Vec<Ipv4Addr>,
|
||||
},
|
||||
WiFi {
|
||||
name: String,
|
||||
ip_addresses: Vec<Ipv4Addr>,
|
||||
hw_address: String,
|
||||
hw_address: HwAddress,
|
||||
state: ActiveConnectionState,
|
||||
strength: u8,
|
||||
},
|
||||
|
|
@ -108,4 +114,11 @@ impl ActiveConnectionInfo {
|
|||
Self::Vpn { name, .. } => name.clone(),
|
||||
}
|
||||
}
|
||||
pub fn hw_address(&self) -> HwAddress {
|
||||
match &self {
|
||||
Self::Wired { hw_address, .. } => *hw_address,
|
||||
Self::WiFi { hw_address, .. } => *hw_address,
|
||||
Self::Vpn { .. } => HwAddress::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
39
cosmic-applet-network/src/network_manager/hw_address.rs
Normal file
39
cosmic-applet-network/src/network_manager/hw_address.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
|
||||
pub struct HwAddress {
|
||||
address: u64,
|
||||
}
|
||||
|
||||
impl HwAddress {
|
||||
pub fn from_str(arg: &str) -> Option<Self> {
|
||||
let columnless_vec = arg.split(":").collect::<Vec<&str>>();
|
||||
if columnless_vec.len() * 3 - 1 != arg.len() {
|
||||
return None;
|
||||
}
|
||||
for byte in &columnless_vec {
|
||||
if byte.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
u64::from_str_radix(columnless_vec.join("").as_str(), 16)
|
||||
.ok()
|
||||
.and_then(|address| Some(HwAddress { address }))
|
||||
}
|
||||
pub fn from_string(arg: &String) -> Option<Self> {
|
||||
HwAddress::from_str(arg.as_str())
|
||||
}
|
||||
pub fn to_string(&self) -> String {
|
||||
// return if self.address > 100000000000000 {
|
||||
// "Intel Corp".to_string()
|
||||
// } else {
|
||||
// "TP-Link".to_string()
|
||||
// };
|
||||
format!("{:#x}", self.address)
|
||||
.trim_start_matches("0x")
|
||||
.chars()
|
||||
.collect::<Vec<_>>()
|
||||
.chunks(2)
|
||||
.map(|chunk| chunk.iter().cloned().collect::<String>())
|
||||
.collect::<Vec<String>>()
|
||||
.join(":")
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ pub mod active_conns;
|
|||
pub mod available_wifi;
|
||||
pub mod current_networks;
|
||||
pub mod devices;
|
||||
pub mod hw_address;
|
||||
pub mod wireless_enabled;
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug, time::Duration};
|
||||
|
|
@ -24,6 +25,7 @@ use futures::{
|
|||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||
SinkExt, StreamExt,
|
||||
};
|
||||
use hw_address::HwAddress;
|
||||
use tokio::process::Command;
|
||||
use zbus::{
|
||||
zvariant::{self, Value},
|
||||
|
|
@ -172,15 +174,19 @@ async fn start_listening(
|
|||
};
|
||||
_ = output.send(response).await;
|
||||
}
|
||||
Some(NetworkManagerRequest::Password(ssid, password)) => {
|
||||
Some(NetworkManagerRequest::Password(ssid, password, hw_address)) => {
|
||||
let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
let success = nm_state
|
||||
.connect_wifi(&conn, &ssid, Some(&password))
|
||||
.connect_wifi(&conn, &ssid, Some(&password), hw_address)
|
||||
.await
|
||||
.is_ok();
|
||||
|
||||
let status = Some(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(ssid.clone(), password.clone()),
|
||||
req: NetworkManagerRequest::Password(
|
||||
ssid.clone(),
|
||||
password.clone(),
|
||||
hw_address,
|
||||
),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
});
|
||||
|
|
@ -190,16 +196,18 @@ async fn start_listening(
|
|||
} else {
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Password(ssid, password),
|
||||
req: NetworkManagerRequest::Password(ssid, password, hw_address),
|
||||
success: false,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => {
|
||||
Some(NetworkManagerRequest::SelectAccessPoint(ssid, hw_address)) => {
|
||||
let state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||
let success = if let Err(err) = state.connect_wifi(&conn, &ssid, None).await {
|
||||
let success = if let Err(err) =
|
||||
state.connect_wifi(&conn, &ssid, None, hw_address).await
|
||||
{
|
||||
tracing::error!("Failed to connect to access point: {:?}", err);
|
||||
false
|
||||
} else {
|
||||
|
|
@ -208,7 +216,7 @@ async fn start_listening(
|
|||
|
||||
_ = output
|
||||
.send(NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone(), hw_address),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})
|
||||
|
|
@ -266,9 +274,9 @@ async fn start_listening(
|
|||
pub enum NetworkManagerRequest {
|
||||
SetAirplaneMode(bool),
|
||||
SetWiFi(bool),
|
||||
SelectAccessPoint(String),
|
||||
SelectAccessPoint(String, HwAddress),
|
||||
Disconnect(String),
|
||||
Password(String, String),
|
||||
Password(String, String, HwAddress),
|
||||
Forget(String),
|
||||
Reload,
|
||||
}
|
||||
|
|
@ -382,7 +390,10 @@ impl NetworkManagerState {
|
|||
let known_access_points: Vec<_> = wireless_access_points
|
||||
.iter()
|
||||
.filter(|a| {
|
||||
known_ssid.contains(&a.ssid) && !active_conns.iter().any(|ac| ac.name() == a.ssid)
|
||||
known_ssid.contains(&a.ssid)
|
||||
&& !active_conns
|
||||
.iter()
|
||||
.any(|ac| ac.name() == a.ssid && ac.hw_address() == a.hw_address)
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
|
@ -407,6 +418,7 @@ impl NetworkManagerState {
|
|||
conn: &Connection,
|
||||
ssid: &str,
|
||||
password: Option<&str>,
|
||||
hw_address: HwAddress,
|
||||
) -> anyhow::Result<()> {
|
||||
let nm = NetworkManager::new(conn).await?;
|
||||
|
||||
|
|
@ -423,7 +435,7 @@ impl NetworkManagerState {
|
|||
let Some(ap) = self
|
||||
.wireless_access_points
|
||||
.iter()
|
||||
.find(|ap| ap.ssid == ssid)
|
||||
.find(|ap| ap.ssid == ssid && ap.hw_address == hw_address)
|
||||
else {
|
||||
return Err(anyhow::anyhow!("Access point not found"));
|
||||
};
|
||||
|
|
@ -468,13 +480,19 @@ impl NetworkManagerState {
|
|||
let settings = c.get_settings().await.ok().unwrap_or_default();
|
||||
|
||||
let s = Settings::new(settings);
|
||||
let cur_hw_address = s
|
||||
.wifi
|
||||
.as_ref()
|
||||
.and_then(|w| w.assigned_mac_address.as_ref())
|
||||
.and_then(|mac| HwAddress::from_string(&mac));
|
||||
// s.wifi.clone().
|
||||
if let Some(cur_ssid) = s
|
||||
.wifi
|
||||
.clone()
|
||||
.and_then(|w| w.ssid)
|
||||
.and_then(|ssid| String::from_utf8(ssid).ok())
|
||||
{
|
||||
if cur_ssid == ssid {
|
||||
if cur_ssid == ssid && hw_address == cur_hw_address.unwrap_or_default() {
|
||||
known_conn = Some(c);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue