feat(control-center/network): add provisory support for wireless connections

I call it "provisory" because I don't have a Wi-Fi card to test it, but in theory, everything should work
This commit is contained in:
retrozinndev
2025-06-19 19:10:25 -03:00
parent ca31a64234
commit e02f96b151
3 changed files with 146 additions and 48 deletions
+124 -24
View File
@@ -1,11 +1,15 @@
import { Gtk, Widget } from "astal/gtk3";
import { Page, PageButton } from "./Page";
import AstalNetwork from "gi://AstalNetwork";
import { bind } from "astal";
import { bind, GLib } from "astal";
import NM from "gi://NM";
import { Windows } from "../../../windows";
import { tr } from "../../../i18n/intl";
import { execApp } from "../../../scripts/apps";
import { EntryPopup, EntryPopupProps } from "../../EntryPopup";
import { Notifications } from "../../../scripts/notifications";
import { AskPopup, AskPopupProps } from "../../AskPopup";
import { encoder } from "../../../scripts/utils";
export const PageNetwork: (() => Page) = () => new Page({
id: "network",
@@ -77,30 +81,126 @@ export const PageNetwork: (() => Page) = () => new Page({
visible: bind(AstalNetwork.get_default(), "primary").as((primary) => primary === AstalNetwork.Primary.WIFI),
hexpand: true,
orientation: Gtk.Orientation.VERTICAL,
children: AstalNetwork.get_default().wifi ? bind(AstalNetwork.get_default().wifi.get_device(), "accessPoints").as((aps) =>
aps.map(ap => new Widget.Button({
hexpand: true,
onClick: () => console.log("connect to " + ap.get_ssid().toArray().toString()), // TODO I don't have a WiFi board :(
child: new Widget.Box({
hexpand: true,
children: [
new Widget.Icon({
halign: Gtk.Align.START,
className: "icon",
icon: "network-wireless-signal-excellent-symbolic"
} as Widget.IconProps),
new Widget.Label({
className: "ssid",
halign: Gtk.Align.START,
label: (getDecoded(ap.ssid.get_data()) ?? ap.ssid.get_data().toString()) ?? "Wi-Fi"
} as Widget.LabelProps),
new Widget.Label({
className: "status",
} as Widget.LabelProps)
]
} as Widget.BoxProps)
} as Widget.ButtonProps))) : [],
children: AstalNetwork.get_default().wifi ? bind(AstalNetwork.get_default().wifi, "accessPoints").as((aps) => [
new Widget.Label({
className: "sub-header",
label: "Wi-Fi"
} as Widget.LabelProps),
...aps.filter(ap => ap.ssid).map(ap => PageButton({
className: bind(AstalNetwork.get_default().wifi, "activeAccessPoint").as(activeAP =>
activeAP.ssid === ap.ssid ? "active" : ""),
title: bind(ap, "ssid").as(ssid =>
ssid ?? "Unknown SSID"),
icon: bind(ap, "iconName"),
endWidget: new Widget.Icon({
icon: bind(ap, "flags").as(flags => flags & NM.__80211ApFlags.PRIVACY ?
"channel-secure-symbolic"
: "channel-insecure-symbolic"),
css: "font-size: 18px;"
} as Widget.IconProps),
extraButtons: [
new Widget.Button({
image: new Widget.Icon({
icon: "window-close-symbolic",
css: "font-size: 18px;"
} as Widget.IconProps)
} as Widget.ButtonProps)
],
onClick: () => {
const ssid: string = ap.ssid ?? "Unknown SSID",
ssidBytes = GLib.Bytes.new(encoder.encode(ssid));
const connection = new NM.Connection();
const setting = NM.SettingWireless.new();
setting.ssid = ssidBytes;
setting.bssid = ap.bssid;
connection.add_setting(setting);
// Check if access point has encryption(needs a password)
if(ap.flags & NM.__80211ApFlags.PRIVACY) {
const passwdPopup = EntryPopup({
isPassword: true,
title: `${tr("connect")}: ${ssid}`,
acceptText: tr("connect"),
closeOnAccept: false,
text: `Input password for ${ssid}`,
onAccept: (input) => {
const pskSetting = NM.SettingWirelessSecurity.new();
pskSetting.keyMgmt = "wpa-psk";
if(ap.flags & NM.__80211ApSecurityFlags.KEY_MGMT_SAE)
pskSetting.keyMgmt = "sae";
pskSetting.psk = input;
AstalNetwork.get_default().get_client().add_connection_async(
connection, true, null, (client, asyncRes) => {
const remoteConnection = client!.add_connection_finish(asyncRes);
if(!remoteConnection) {
notifyConnectionError(ssid);
return;
}
passwdPopup.close();
saveToDisk(remoteConnection, ssid);
}
);
},
} as EntryPopupProps);
return;
}
AstalNetwork.get_default().get_client().add_connection_async(connection, false, null, (_, asyncRes) => {
const remoteConnection = AstalNetwork.get_default().get_client().add_connection_finish(asyncRes);
if(!remoteConnection) {
notifyConnectionError(ssid);
return;
}
activateWirelessConnection(remoteConnection, ssid);
});
}
}))
]
) : [],
} as Widget.BoxProps)
]
});
function activateWirelessConnection(connection: NM.RemoteConnection, ssid: string): void {
AstalNetwork.get_default().get_client().activate_connection_async(
connection, AstalNetwork.get_default().wifi.get_device(), null, null, (_, asyncRes) => {
const activeConnection = AstalNetwork.get_default().get_client().activate_connection_finish(asyncRes);
if(!activeConnection) {
Notifications.getDefault().sendNotification({
appName: "network",
summary: "Couldn't activate wireless connection",
body: `An error occurred while activating the wireless connection "${ssid}"`
});
return;
}
}
);
}
function notifyConnectionError(ssid: string): void {
Notifications.getDefault().sendNotification({
appName: "network",
summary: "Coudn't connect Wi-Fi",
body: `An error occurred while trying to connect to the "${ssid}" access point. \nMaybe the password is invalid?`
});
}
function saveToDisk(remoteConnection: NM.RemoteConnection, ssid: string): void {
AskPopup({
text: `Save password for connection "${ssid}"?`,
acceptText: "Yes",
onAccept: () => remoteConnection.commit_changes_async(true, null, (_, asyncRes) =>
!remoteConnection.commit_changes_finish(asyncRes) && Notifications.getDefault().sendNotification({
appName: "network",
summary: "Couldn't save Wi-Fi password",
body: `An error occurred while trying to write the password for "${ssid}" to disk`
}))
} as AskPopupProps);
}