303 lines
11 KiB
Rust
303 lines
11 KiB
Rust
use cosmic::Element;
|
|
use cosmic::iced::{Alignment, Length};
|
|
use cosmic::widget::{column, row, text_input};
|
|
use zeroize::{Zeroize, Zeroizing};
|
|
|
|
use super::ui::{Input, message};
|
|
use super::{Command, Security};
|
|
use crate::{App, Message, visuals};
|
|
|
|
impl App {
|
|
pub(super) fn wifi_view(
|
|
&self,
|
|
result: &Result<super::wifi::Wifi, String>,
|
|
) -> Element<'_, Message> {
|
|
let s = &self.connections;
|
|
let p = visuals::Palette::from_resolved(&self.resolved.presented);
|
|
let ready = s.busy.is_none();
|
|
let Ok(wifi) = result else {
|
|
return self.connection_card(
|
|
column([])
|
|
.spacing(8)
|
|
.push(self.label(ferese_config::tr!("Wi-Fi unavailable"), 14.))
|
|
.push(self.connection_note(result.as_ref().expect_err(
|
|
"the unavailable-services branch contains a connection error",
|
|
))),
|
|
);
|
|
};
|
|
let mut body = column([]).spacing(6);
|
|
let status = if wifi.radios.is_empty() {
|
|
"No Wi-Fi adapter"
|
|
} else if !wifi.hardware_enabled {
|
|
"Blocked by a hardware switch or airplane mode"
|
|
} else if wifi.enabled {
|
|
"On"
|
|
} else {
|
|
"Off"
|
|
};
|
|
body = body.push(
|
|
self.connection_card(
|
|
row([])
|
|
.spacing(8)
|
|
.align_y(Alignment::Center)
|
|
.push(
|
|
column([])
|
|
.spacing(2)
|
|
.width(Length::Fill)
|
|
.push(self.label(ferese_config::tr!("Wi-Fi"), 15.))
|
|
.push(self.connection_note(status)),
|
|
)
|
|
.push(
|
|
ferese_theme::controls::switch(wifi.enabled, p)
|
|
.name(ferese_config::tr!("Wi-Fi power"))
|
|
.on_press_maybe(
|
|
(ready
|
|
&& (wifi.hardware_enabled || wifi.enabled)
|
|
&& !wifi.radios.is_empty())
|
|
.then(|| message(Input::Run(Command::WifiPower(!wifi.enabled)))),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
if !wifi.enabled || !wifi.hardware_enabled || wifi.radios.is_empty() {
|
|
return body.into();
|
|
}
|
|
body = body.push(
|
|
row([])
|
|
.align_y(Alignment::Center)
|
|
.push(
|
|
self.label(ferese_config::tr!("Networks"), 14.)
|
|
.width(Length::Fill),
|
|
)
|
|
.push(self.connection_button("Scan", Input::Run(Command::WifiScan), ready, false)),
|
|
);
|
|
if wifi.networks.is_empty() {
|
|
body = body
|
|
.push(self.connection_note("No networks found. Scan to look for nearby networks."));
|
|
}
|
|
for network in &wifi.networks {
|
|
let radio = wifi
|
|
.radios
|
|
.iter()
|
|
.find(|r| r.path == network.device)
|
|
.map(|r| r.name.as_str())
|
|
.unwrap_or("");
|
|
let state = if network.connected {
|
|
"Connected · "
|
|
} else if network.connecting {
|
|
"Connecting · "
|
|
} else if network.saved.is_some() {
|
|
"Saved · "
|
|
} else {
|
|
""
|
|
};
|
|
let state = ferese_config::locale::text(state);
|
|
let detail = format!(
|
|
"{state}{} · {}{}",
|
|
ferese_config::locale::text(network.security.label()),
|
|
ferese_config::locale::format(
|
|
"{percent}% signal",
|
|
&[("percent", network.strength.to_string())]
|
|
),
|
|
if wifi.radios.len() > 1 {
|
|
format!(" · {radio}")
|
|
} else {
|
|
String::new()
|
|
}
|
|
);
|
|
let mut controls = row([]).spacing(6);
|
|
if network.connected || network.connecting {
|
|
controls = controls.push(self.connection_button(
|
|
"Disconnect",
|
|
Input::Run(Command::WifiDisconnect(network.device.clone())),
|
|
ready,
|
|
false,
|
|
));
|
|
} else if network.saved.is_some()
|
|
|| !network.security.password() && network.security.can_create()
|
|
{
|
|
controls = controls.push(self.connection_button(
|
|
"Connect",
|
|
Input::Run(Command::WifiConnect(
|
|
network.clone(),
|
|
Zeroizing::new(String::new()),
|
|
)),
|
|
ready,
|
|
false,
|
|
));
|
|
} else {
|
|
controls = controls.push(self.connection_button(
|
|
"Connect…",
|
|
Input::Select(network.clone()),
|
|
ready,
|
|
false,
|
|
));
|
|
}
|
|
if network.saved.is_some() && network.security.password() {
|
|
controls = controls.push(self.connection_button(
|
|
"Password…",
|
|
Input::Select(network.clone()),
|
|
ready,
|
|
false,
|
|
));
|
|
}
|
|
body = body.push(
|
|
self.connection_card(
|
|
row([])
|
|
.spacing(8)
|
|
.align_y(Alignment::Center)
|
|
.push(visuals::action_icon(
|
|
super::super::schema::Page::Connections.icon(),
|
|
p.accent,
|
|
))
|
|
.push(
|
|
column([])
|
|
.spacing(2)
|
|
.width(Length::Fill)
|
|
.push(self.label(network.name.clone(), 13.))
|
|
.push(self.connection_note(&detail)),
|
|
)
|
|
.push(controls),
|
|
),
|
|
);
|
|
if s.selected.as_ref().is_some_and(|selected| {
|
|
selected.ssid == network.ssid
|
|
&& selected.device == network.device
|
|
&& selected.security == network.security
|
|
}) {
|
|
body = body.push(self.wifi_credentials());
|
|
}
|
|
}
|
|
body = body.push(self.connection_button(
|
|
"Join a hidden network…",
|
|
Input::Hidden(true),
|
|
ready,
|
|
false,
|
|
));
|
|
if s.hidden {
|
|
body = body.push(self.wifi_credentials());
|
|
}
|
|
if !wifi.saved.is_empty() {
|
|
body = body.push(self.label(ferese_config::tr!("Saved networks"), 14.));
|
|
for saved in &wifi.saved {
|
|
body = body.push(
|
|
self.connection_card(
|
|
row([])
|
|
.spacing(8)
|
|
.align_y(Alignment::Center)
|
|
.push(visuals::action_icon(
|
|
crate::schema::Page::Connections.icon(),
|
|
p.muted,
|
|
))
|
|
.push(
|
|
column([])
|
|
.spacing(2)
|
|
.width(Length::Fill)
|
|
.push(self.label(saved.name.clone(), 13.))
|
|
.push(self.connection_note(saved.security.label())),
|
|
)
|
|
.push(self.connection_button(
|
|
"Forget",
|
|
Input::Forget(Command::WifiForget(saved.path.clone())),
|
|
ready,
|
|
false,
|
|
)),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
body.into()
|
|
}
|
|
|
|
pub(super) fn wifi_credentials(&self) -> Element<'_, Message> {
|
|
let s = &self.connections;
|
|
let p = visuals::Palette::from_resolved(&self.resolved.presented);
|
|
let target = self.wifi_target();
|
|
let mut body = column([]).spacing(6).push(self.ui_label(
|
|
if s.hidden {
|
|
ferese_config::locale::translate("Hidden network")
|
|
} else {
|
|
ferese_config::locale::format(
|
|
"Join {network}",
|
|
&[(
|
|
"network",
|
|
s.selected
|
|
.as_ref()
|
|
.map(|n| n.name.clone())
|
|
.unwrap_or_else(|| ferese_config::locale::translate("network")),
|
|
)],
|
|
)
|
|
},
|
|
16.,
|
|
));
|
|
if s.hidden {
|
|
body = body.push(
|
|
text_input(
|
|
ferese_config::tr!("Network name (SSID)"),
|
|
s.hidden_name.clone(),
|
|
)
|
|
.font(self.font)
|
|
.size(13)
|
|
.padding([5, 8])
|
|
.style(visuals::input_style(p))
|
|
.on_input(|name| message(Input::HiddenName(name))),
|
|
);
|
|
let mut choices = row([]).spacing(6);
|
|
for security in [
|
|
Security::Personal,
|
|
Security::Sae,
|
|
Security::Open,
|
|
Security::Owe,
|
|
] {
|
|
choices = choices.push(self.connection_button(
|
|
security.label(),
|
|
Input::HiddenSecurity(security),
|
|
true,
|
|
s.hidden_security == security,
|
|
));
|
|
}
|
|
body = body.push(choices);
|
|
}
|
|
let security = target
|
|
.as_ref()
|
|
.map(|n| n.security)
|
|
.unwrap_or(s.hidden_security);
|
|
if security.password() {
|
|
body = body.push(
|
|
text_input(ferese_config::tr!("Network password"), s.password.as_str())
|
|
.id(cosmic::widget::Id::new("wifi-password"))
|
|
.password()
|
|
.font(self.font)
|
|
.size(13)
|
|
.padding([5, 8])
|
|
.style(visuals::input_style(p))
|
|
.on_input(|value| message(Input::Password(Zeroizing::new(value))))
|
|
.on_submit(|mut value| {
|
|
value.zeroize();
|
|
message(Input::SubmitWifi)
|
|
}),
|
|
);
|
|
}
|
|
if !security.can_create() {
|
|
body = body.push(self.connection_note(
|
|
"Enterprise and legacy networks need a saved NetworkManager profile with their security settings.",
|
|
));
|
|
}
|
|
body = body.push(
|
|
row([])
|
|
.spacing(8)
|
|
.push(self.connection_button("Cancel", Input::CancelWifi, true, false))
|
|
.push(self.connection_button(
|
|
"Connect",
|
|
Input::SubmitWifi,
|
|
target.is_some()
|
|
&& security.can_create()
|
|
&& super::wifi::valid_password(security, &s.password)
|
|
&& s.busy.is_none(),
|
|
true,
|
|
)),
|
|
);
|
|
self.connection_card(body)
|
|
}
|
|
}
|