Skip to content

Commit 5e7eee6

Browse files
committed
Quick setting, add autoconnect toggle to VPN connections
1 parent 7dc9530 commit 5e7eee6

3 files changed

Lines changed: 92 additions & 7 deletions

File tree

cosmic-settings/src/pages/networking/vpn/mod.rs

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ pub enum Message {
8282
UsernameUpdate(String),
8383
/// Display more options for an access point
8484
ViewMore(Option<ConnectionId>),
85+
/// Toggle autoconnect for a VPN connection
86+
ToggleAutoconnect(ConnectionId, String, bool),
8587
/// Create a new wireguard connection
8688
WireGuardConfig,
8789
/// Update the text input for the wireguard device name
@@ -132,7 +134,7 @@ impl From<Message> for crate::pages::Message {
132134
#[derive(Clone, Debug)]
133135
pub enum ConnectionSettings {
134136
Vpn(VpnConnectionSettings),
135-
Wireguard { id: String },
137+
Wireguard { id: String, autoconnect: bool },
136138
}
137139

138140
#[derive(Clone, Debug, Default)]
@@ -141,6 +143,7 @@ pub struct VpnConnectionSettings {
141143
username: Option<String>,
142144
connection_type: Option<ConnectionType>,
143145
password_flag: Option<PasswordFlag>,
146+
autoconnect: bool,
144147
}
145148

146149
impl VpnConnectionSettings {
@@ -496,7 +499,7 @@ impl Page {
496499
if let Some(settings) = self.known_connections.get(&uuid) {
497500
let settings = match settings {
498501
ConnectionSettings::Vpn(settings) => settings,
499-
ConnectionSettings::Wireguard { id } => {
502+
ConnectionSettings::Wireguard { id, .. } => {
500503
let connection_name = id.clone();
501504
return cosmic::task::future(async move {
502505
if let Err(why) = nmcli::connect(&connection_name).await {
@@ -563,6 +566,22 @@ impl Page {
563566
self.view_more_popup = None;
564567
self.dialog = Some(VpnDialog::RemoveProfile(uuid));
565568
}
569+
Message::ToggleAutoconnect(uuid, connection_name, enabled) => {
570+
if let Some(settings) = self.known_connections.get_mut(&uuid) {
571+
match settings {
572+
ConnectionSettings::Vpn(vpn) => vpn.autoconnect = enabled,
573+
ConnectionSettings::Wireguard { autoconnect, .. } => {
574+
*autoconnect = enabled
575+
}
576+
}
577+
}
578+
return cosmic::task::future(async move {
579+
match nmcli::set_autoconnect(&connection_name, enabled).await {
580+
Ok(_) => Message::Refresh,
581+
Err(why) => Message::Error(ErrorKind::Config, why.to_string()),
582+
}
583+
});
584+
}
566585
Message::RemoveProfile(uuid) => {
567586
self.dialog = None;
568587
self.close_popup_and_apply_updates();
@@ -977,6 +996,7 @@ fn devices_view() -> Section<crate::pages::Message> {
977996
crate::slab!(descriptions {
978997
vpn_conns_txt = fl!("vpn", "connections");
979998
remove_txt = fl!("vpn", "remove");
999+
autoconnect_txt = fl!("vpn", "autoconnect");
9801000
connect_txt = fl!("connect");
9811001
connected_txt = fl!("connected");
9821002
settings_txt = fl!("settings");
@@ -1008,9 +1028,13 @@ fn devices_view() -> Section<crate::pages::Message> {
10081028
let known_networks = page.known_connections.iter().fold(
10091029
vpn_connections,
10101030
|networks, (uuid, connection)| {
1011-
let id = match connection {
1012-
ConnectionSettings::Vpn(connection) => connection.id.as_str(),
1013-
ConnectionSettings::Wireguard { id } => id.as_str(),
1031+
let (id, autoconnect) = match connection {
1032+
ConnectionSettings::Vpn(connection) => {
1033+
(connection.id.as_str(), connection.autoconnect)
1034+
}
1035+
ConnectionSettings::Wireguard { id, autoconnect } => {
1036+
(id.as_str(), *autoconnect)
1037+
}
10141038
};
10151039

10161040
let is_connected = active_conns.iter().any(|conn| match conn {
@@ -1061,11 +1085,42 @@ fn devices_view() -> Section<crate::pages::Message> {
10611085
Message::Settings(uuid.clone()),
10621086
&section.descriptions[settings_txt],
10631087
))
1088+
.push({
1089+
let uuid = uuid.clone();
1090+
let id_owned = id.to_owned();
1091+
widget::row::with_capacity(3)
1092+
.push(
1093+
widget::text::body(
1094+
&section.descriptions[autoconnect_txt],
1095+
)
1096+
.align_y(Alignment::Center),
1097+
)
1098+
.push(horizontal_space())
1099+
.push(
1100+
widget::toggler(autoconnect).on_toggle(
1101+
move |val| {
1102+
Message::ToggleAutoconnect(
1103+
uuid.clone(),
1104+
id_owned.clone(),
1105+
val,
1106+
)
1107+
},
1108+
),
1109+
)
1110+
.align_y(Alignment::Center)
1111+
.apply(widget::container)
1112+
.padding([
1113+
spacing.space_xxxs,
1114+
spacing.space_s,
1115+
spacing.space_xxxs,
1116+
spacing.space_xs,
1117+
])
1118+
})
10641119
.push(popup_button(
10651120
Message::RemoveProfileRequest(uuid.clone()),
10661121
&section.descriptions[remove_txt],
10671122
))
1068-
.width(Length::Fixed(200.0))
1123+
.width(Length::Fixed(260.0))
10691124
.apply(widget::container)
10701125
.padding(cosmic::theme::spacing().space_xxs)
10711126
.class(cosmic::theme::Container::Dropdown),
@@ -1222,7 +1277,14 @@ fn connection_settings(conn: zbus::Connection) -> Task<crate::app::Message> {
12221277
"wireguard" => {
12231278
let id = connection.get("id")?.downcast_ref::<String>().ok()?;
12241279
let uuid = connection.get("uuid")?.downcast_ref::<String>().ok()?;
1225-
return Some((Arc::from(uuid), ConnectionSettings::Wireguard { id }));
1280+
let autoconnect = connection
1281+
.get("autoconnect")
1282+
.and_then(|v| v.downcast_ref::<bool>().ok())
1283+
.unwrap_or(true);
1284+
return Some((
1285+
Arc::from(uuid),
1286+
ConnectionSettings::Wireguard { id, autoconnect },
1287+
));
12261288
}
12271289

12281290
_ => return None,
@@ -1268,13 +1330,19 @@ fn connection_settings(conn: zbus::Connection) -> Task<crate::app::Message> {
12681330
})
12691331
.unwrap_or_default();
12701332

1333+
let autoconnect = connection
1334+
.get("autoconnect")
1335+
.and_then(|v| v.downcast_ref::<bool>().ok())
1336+
.unwrap_or(true);
1337+
12711338
Some((
12721339
Arc::from(uuid),
12731340
ConnectionSettings::Vpn(VpnConnectionSettings {
12741341
id,
12751342
connection_type,
12761343
password_flag,
12771344
username,
1345+
autoconnect,
12781346
}),
12791347
))
12801348
})

cosmic-settings/src/pages/networking/vpn/nmcli.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ pub async fn add_fallback(connection_name: &str) -> Result<(), String> {
2828
.apply(crate::utils::map_stderr_output)
2929
}
3030

31+
pub async fn set_autoconnect(connection_name: &str, autoconnect: bool) -> Result<(), String> {
32+
let value = if autoconnect { "yes" } else { "no" };
33+
tokio::process::Command::new("nmcli")
34+
.args([
35+
"con",
36+
"mod",
37+
connection_name,
38+
"connection.autoconnect",
39+
value,
40+
])
41+
.stderr(Stdio::piped())
42+
.output()
43+
.await
44+
.apply(crate::utils::map_stderr_output)
45+
}
46+
3147
pub async fn connect(connection_name: &str) -> Result<(), String> {
3248
tokio::process::Command::new("nmcli")
3349
.args(["con", "up", connection_name])

i18n/en/cosmic_settings.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ remove-connection-dialog = Remove connection profile?
188188
.wired-description = You'll need to recreate this profile to use it in the future.
189189
190190
vpn = VPN
191+
.autoconnect = Connect automatically
191192
.connections = VPN connections
192193
.error = Failed to add VPN config
193194
.remove = Remove connection profile

0 commit comments

Comments
 (0)