Fix network list flickering on refresh
This commit is contained in:
93
modules/menus/network/wifi/APStaging.js
Normal file
93
modules/menus/network/wifi/APStaging.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const renderWapStaging = (self, network, staging, connecting) => {
|
||||
Utils.merge([network.bind("wifi"), staging.bind("value")], () => {
|
||||
console.log(JSON.stringify(network, null, 2));
|
||||
if (!Object.keys(staging.value).length) {
|
||||
return (self.child = Widget.Box());
|
||||
}
|
||||
|
||||
return (self.child = Widget.Box({
|
||||
class_name: "network-element-item staging",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hpack: "fill",
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Icon({
|
||||
class_name: `network-icon wifi `,
|
||||
icon: `${staging.value.iconName}`,
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "connection-container",
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "active-connection",
|
||||
hpack: "start",
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
label: staging.value.ssid,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Revealer({
|
||||
hpack: "end",
|
||||
reveal_child: connecting
|
||||
.bind("value")
|
||||
.as((c) => staging.value.bssid === c),
|
||||
child: Widget.Spinner({
|
||||
class_name: "spinner wap",
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "network-password-input-container",
|
||||
hpack: "fill",
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Entry({
|
||||
hpack: "start",
|
||||
hexpand: true,
|
||||
visibility: false,
|
||||
class_name: "network-password-input",
|
||||
placeholder_text: "enter password",
|
||||
onAccept: (selfInp) => {
|
||||
connecting.value = staging.value.bssid;
|
||||
Utils.execAsync(
|
||||
`nmcli dev wifi connect ${staging.value.bssid} password ${selfInp.text}`,
|
||||
)
|
||||
.catch((err) => {
|
||||
connecting.value = "";
|
||||
console.error(
|
||||
`Failed to connect to wifi: ${staging.value.ssid}... ${err}`,
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
connecting.value = "";
|
||||
staging.value = {};
|
||||
});
|
||||
selfInp.text = "";
|
||||
},
|
||||
}),
|
||||
Widget.Button({
|
||||
hpack: "end",
|
||||
class_name: "close-network-password-input-button",
|
||||
on_primary_click: () => {
|
||||
connecting.value = "";
|
||||
staging.value = {};
|
||||
},
|
||||
child: Widget.Icon({
|
||||
class_name: "close-network-password-input-icon",
|
||||
icon: "window-close-symbolic",
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
export { renderWapStaging };
|
||||
178
modules/menus/network/wifi/WirelessAPs.js
Normal file
178
modules/menus/network/wifi/WirelessAPs.js
Normal file
@@ -0,0 +1,178 @@
|
||||
const renderWAPs = (self, network, staging, connecting) => {
|
||||
const getIdBySsid = (ssid, nmcliOutput) => {
|
||||
const lines = nmcliOutput.trim().split("\n");
|
||||
for (const line of lines) {
|
||||
const columns = line.trim().split(/\s{2,}/);
|
||||
if (columns[0].includes(ssid)) {
|
||||
return columns[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const WifiStatusMap = {
|
||||
unknown: "Status Unknown",
|
||||
unmanaged: "Unmanaged",
|
||||
unavailable: "Unavailable",
|
||||
disconnected: "Disconnected",
|
||||
prepare: "Preparing Connecting",
|
||||
config: "Connecting",
|
||||
need_auth: "Needs Authentication",
|
||||
ip_config: "Requesting IP",
|
||||
ip_check: "Checking Access",
|
||||
secondaries: "Waiting on Secondaries",
|
||||
activated: "Connected",
|
||||
deactivating: "Disconnecting",
|
||||
failed: "Connection Failed",
|
||||
};
|
||||
self.hook(network, () => {
|
||||
Utils.merge(
|
||||
[network.bind("wifi"), staging.bind("value"), connecting.bind("value")],
|
||||
() => {
|
||||
const WAPs = network.wifi.access_points;
|
||||
|
||||
const isInStaging = (wap) => {
|
||||
if (Object.keys(staging.value).length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wap.bssid === staging.value.bssid;
|
||||
};
|
||||
|
||||
const filteredWAPs = WAPs.filter(
|
||||
(ap) => ap.ssid !== "Unknown" && !isInStaging(ap),
|
||||
).sort((a, b) => {
|
||||
if (network.wifi.ssid === a.ssid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (network.wifi.ssid === b.ssid) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return b.strength - a.strength;
|
||||
});
|
||||
|
||||
if (
|
||||
filteredWAPs.length <= 0 &&
|
||||
Object.keys(staging.value).length === 0
|
||||
) {
|
||||
return (self.child = Widget.Label({
|
||||
class_name: "waps-not-found dim",
|
||||
expand: true,
|
||||
hpack: "center",
|
||||
vpack: "center",
|
||||
label: "No Wi-Fi Networks Found",
|
||||
}));
|
||||
}
|
||||
return (self.children = filteredWAPs.map((ap) => {
|
||||
return Widget.Box({
|
||||
children: [
|
||||
Widget.Button({
|
||||
on_primary_click: () => {
|
||||
connecting.value = ap.bssid;
|
||||
Utils.execAsync(`nmcli device wifi connect ${ap.bssid}`)
|
||||
.then(() => {
|
||||
connecting.value = "";
|
||||
staging.value = {};
|
||||
})
|
||||
.catch((err) => {
|
||||
if (
|
||||
err
|
||||
.toLowerCase()
|
||||
.includes("secrets were required, but not provided")
|
||||
) {
|
||||
staging.value = ap;
|
||||
}
|
||||
connecting.value = "";
|
||||
});
|
||||
},
|
||||
class_name: "network-element-item",
|
||||
child: Widget.Box({
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
hpack: "start",
|
||||
hexpand: true,
|
||||
children: [
|
||||
Widget.Icon({
|
||||
class_name: `network-icon wifi ${ap.ssid === network.wifi.ssid ? "active" : ""}`,
|
||||
icon: `${ap["iconName"]}`,
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "connection-container",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Label({
|
||||
class_name: "active-connection",
|
||||
hpack: "start",
|
||||
truncate: "end",
|
||||
wrap: true,
|
||||
label: ap.ssid,
|
||||
}),
|
||||
Widget.Revealer({
|
||||
revealChild: ap.ssid === network.wifi.ssid,
|
||||
child: Widget.Label({
|
||||
hpack: "start",
|
||||
class_name: "connection-status dim",
|
||||
label:
|
||||
WifiStatusMap[
|
||||
network.wifi.state.toLowerCase()
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Widget.Revealer({
|
||||
hpack: "end",
|
||||
vpack: "start",
|
||||
reveal_child: ap.bssid === connecting.value,
|
||||
child: Widget.Spinner({
|
||||
vpack: "start",
|
||||
class_name: "spinner wap",
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
Widget.Revealer({
|
||||
vpack: "start",
|
||||
reveal_child: ap.bssid !== connecting.value && ap.active,
|
||||
child: Widget.Button({
|
||||
vpack: "start",
|
||||
tooltip_text: "Delete/Forget Network",
|
||||
class_name: "menu-icon-button network disconnect",
|
||||
on_primary_click: () => {
|
||||
connecting.value = ap.bssid;
|
||||
Utils.execAsync("nmcli connection show --active").then(
|
||||
() => {
|
||||
Utils.execAsync("nmcli connection show --active").then(
|
||||
(res) => {
|
||||
const connectionId = getIdBySsid(ap.ssid, res);
|
||||
|
||||
Utils.execAsync(
|
||||
`nmcli connection delete ${connectionId} "${ap.ssid}"`,
|
||||
).catch((err) =>
|
||||
console.error(
|
||||
`Error while forgetting "${ap.ssid}": ${err}`,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Widget.Label(""),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
});
|
||||
}));
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export { renderWAPs };
|
||||
46
modules/menus/network/wifi/index.js
Normal file
46
modules/menus/network/wifi/index.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const network = await Service.import("network");
|
||||
import { renderWAPs } from "./WirelessAPs.js";
|
||||
import { renderWapStaging } from "./APStaging.js";
|
||||
|
||||
const Staging = Variable({});
|
||||
const Connecting = Variable("");
|
||||
|
||||
const Wifi = () => {
|
||||
return Widget.Box({
|
||||
class_name: "menu-section-container wifi",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "menu-label-container",
|
||||
hpack: "fill",
|
||||
child: Widget.Label({
|
||||
class_name: "menu-label",
|
||||
hexpand: true,
|
||||
hpack: "center",
|
||||
label: "Wi-Fi",
|
||||
}),
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "menu-items-section",
|
||||
vertical: true,
|
||||
children: [
|
||||
Widget.Box({
|
||||
class_name: "wap-staging",
|
||||
setup: (self) => {
|
||||
renderWapStaging(self, network, Staging, Connecting);
|
||||
},
|
||||
}),
|
||||
Widget.Box({
|
||||
class_name: "available-waps",
|
||||
vertical: true,
|
||||
setup: (self) => {
|
||||
renderWAPs(self, network, Staging, Connecting);
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
export { Wifi };
|
||||
Reference in New Issue
Block a user