Finish Network Menu rework...
This commit is contained in:
14
config.js
14
config.js
@@ -42,17 +42,5 @@ App.config({
|
|||||||
launcher: 350,
|
launcher: 350,
|
||||||
bar0: 350,
|
bar0: 350,
|
||||||
},
|
},
|
||||||
onConfigParsed: () =>
|
onConfigParsed: () => Utils.execAsync(`python3 ${App.configDir}/services/bluetooth.py`),
|
||||||
Utils.subprocess(
|
|
||||||
[
|
|
||||||
"python3",
|
|
||||||
`${App.configDir}/services/bluetooth.py`,
|
|
||||||
],
|
|
||||||
|
|
||||||
// callback when the program outputs something to stdout
|
|
||||||
(output) => console.info(output),
|
|
||||||
|
|
||||||
// callback on error
|
|
||||||
(err) => console.info(err),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,37 +1,90 @@
|
|||||||
const renderWapStaging = (self, stagedDevice) => {
|
const renderWapStaging = (self, network, staging, connecting) => {
|
||||||
self.hook(stagedDevice, ({ value }) => {
|
Utils.merge([network.bind("wifi"), staging.bind("value")], () => {
|
||||||
return (self.child = Widget.Button({
|
if (!Object.keys(staging.value).length) {
|
||||||
class_name: "network-element-item",
|
return (self.child = Widget.Box());
|
||||||
child: Widget.Box({
|
}
|
||||||
hpack: "start",
|
|
||||||
children: [
|
return (self.child = Widget.Box({
|
||||||
Widget.Icon({
|
class_name: "network-element-item staging",
|
||||||
class_name: "network-ethernet-icon",
|
vertical: true,
|
||||||
icon: `${stagedDevice["iconName"]}`,
|
children: [
|
||||||
}),
|
Widget.Box({
|
||||||
Widget.Box({
|
hpack: "fill",
|
||||||
class_name: "connection-container",
|
hexpand: true,
|
||||||
vertical: true,
|
children: [
|
||||||
children: [
|
Widget.Icon({
|
||||||
Widget.Label({
|
class_name: "network-ethernet-icon",
|
||||||
class_name: "active-connection",
|
icon: `${staging.value.iconName}`,
|
||||||
hpack: "start",
|
}),
|
||||||
truncate: "end",
|
Widget.Box({
|
||||||
wrap: true,
|
class_name: "connection-container",
|
||||||
label: stagedDevice.ssid,
|
hexpand: true,
|
||||||
}),
|
vertical: true,
|
||||||
Widget.Revealer({
|
children: [
|
||||||
revealChild: stagedDevice.active,
|
Widget.Label({
|
||||||
child: Widget.Label({
|
class_name: "active-connection",
|
||||||
hpack: "start",
|
hpack: "start",
|
||||||
class_name: "connection-status dim",
|
truncate: "end",
|
||||||
label: "Connected",
|
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",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,60 +1,177 @@
|
|||||||
const renderWAPs = (self, network) => {
|
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, () => {
|
self.hook(network, () => {
|
||||||
const WAPs = network.wifi.access_points;
|
Utils.merge(
|
||||||
|
[network.bind("wifi"), staging.bind("value"), connecting.bind("value")],
|
||||||
|
() => {
|
||||||
|
const WAPs = network.wifi.access_points;
|
||||||
|
|
||||||
console.log("WAPs");
|
const isInStaging = (wap) => {
|
||||||
console.log(JSON.stringify(WAPs, null, 2));
|
if (Object.keys(staging.value).length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const filteredWAPs = WAPs.filter((ap) => ap.ssid !== "Unknown").sort(
|
return wap.bssid === staging.value.bssid;
|
||||||
(a, b) => {
|
};
|
||||||
return b.strength - a.strength;
|
|
||||||
|
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((res) => {
|
||||||
|
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-ethernet-icon",
|
||||||
|
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(""),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (filteredWAPs.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.Button({
|
|
||||||
class_name: "network-element-item",
|
|
||||||
child: Widget.Box({
|
|
||||||
hpack: "start",
|
|
||||||
children: [
|
|
||||||
Widget.Icon({
|
|
||||||
class_name: "network-ethernet-icon",
|
|
||||||
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.active,
|
|
||||||
child: Widget.Label({
|
|
||||||
hpack: "start",
|
|
||||||
class_name: "connection-status dim",
|
|
||||||
label: "Connected",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ const network = await Service.import("network");
|
|||||||
import { renderWAPs } from "./WirelessAPs.js";
|
import { renderWAPs } from "./WirelessAPs.js";
|
||||||
import { renderWapStaging } from "./APStaging.js";
|
import { renderWapStaging } from "./APStaging.js";
|
||||||
|
|
||||||
const Staging = Variable("none");
|
const Staging = Variable({});
|
||||||
|
const Connecting = Variable("");
|
||||||
|
|
||||||
const Wifi = () => {
|
const Wifi = () => {
|
||||||
return Widget.Box({
|
return Widget.Box({
|
||||||
@@ -26,14 +27,14 @@ const Wifi = () => {
|
|||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "wap-staging",
|
class_name: "wap-staging",
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
renderWapStaging(self, Staging);
|
renderWapStaging(self, network, Staging, Connecting);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Widget.Box({
|
Widget.Box({
|
||||||
class_name: "available-waps",
|
class_name: "available-waps",
|
||||||
vertical: true,
|
vertical: true,
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
renderWAPs(self, network);
|
renderWAPs(self, network, Staging, Connecting);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
min-width: 27em;
|
min-width: 27em;
|
||||||
min-height: 6em;
|
min-height: 6em;
|
||||||
background: $crust;
|
background: $crust;
|
||||||
border: 0.13em solid $surface0; border-radius: 0.4em;
|
border: 0.13em solid $surface0;
|
||||||
|
border-radius: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-content.calendarmenu-window {
|
.window-content.calendarmenu-window {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ tooltip label {
|
|||||||
.menu-items {
|
.menu-items {
|
||||||
background: $crust;
|
background: $crust;
|
||||||
border: .13em solid $surface0;
|
border: .13em solid $surface0;
|
||||||
border-radius: .5rem;
|
border-radius: .7rem;
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
color: $text;
|
color: $text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,41 @@
|
|||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.staging {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $mauve;
|
color: $mauve;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.spinner.wap {
|
||||||
|
color: $mauve;
|
||||||
|
}
|
||||||
|
|
||||||
|
.network-password-input-container {
|
||||||
|
background: $mantle;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
margin: 0em 2em;
|
||||||
|
margin-top: 0.75em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-network-password-input-button {
|
||||||
|
padding: 0em 0.5em;
|
||||||
|
&:hover image {
|
||||||
|
color: $maroon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-icon-button.network.disconnect {
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
label {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: $maroon;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
min-width: 26em;
|
min-width: 26em;
|
||||||
min-height: 6em;
|
min-height: 6em;
|
||||||
background: $crust;
|
background: $crust;
|
||||||
border: 0.13em solid $surface0; border-radius: 0.4em;
|
border: 0.13em solid $surface0;
|
||||||
|
border-radius: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-content.notificationsmenu-window {
|
.window-content.notificationsmenu-window {
|
||||||
|
|||||||
34
style.css
34
style.css
@@ -497,7 +497,7 @@ tooltip label {
|
|||||||
.menu-items {
|
.menu-items {
|
||||||
background: #11111b;
|
background: #11111b;
|
||||||
border: 0.13em solid #313244;
|
border: 0.13em solid #313244;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.7rem;
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
color: #cdd6f4;
|
color: #cdd6f4;
|
||||||
}
|
}
|
||||||
@@ -848,9 +848,37 @@ window#powermenu .powermenu.box {
|
|||||||
.menu-items-container.network .network-element-item:not(:last-child) {
|
.menu-items-container.network .network-element-item:not(:last-child) {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
.menu-items-container.network .network-element-item.staging {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
.menu-items-container.network .network-element-item:hover {
|
.menu-items-container.network .network-element-item:hover {
|
||||||
color: #cba6f7;
|
color: #cba6f7;
|
||||||
}
|
}
|
||||||
|
.menu-items-container.network .spinner.wap {
|
||||||
|
color: #cba6f7;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .network-password-input-container {
|
||||||
|
background: #181825;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
margin: 0em 2em;
|
||||||
|
margin-top: 0.75em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .close-network-password-input-button {
|
||||||
|
padding: 0em 0.5em;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .close-network-password-input-button:hover image {
|
||||||
|
color: #eba0ac;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .menu-icon-button.network.disconnect {
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .menu-icon-button.network.disconnect label {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
.menu-items-container.network .menu-icon-button.network.disconnect:hover {
|
||||||
|
color: #eba0ac;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-dropdown-label.bluetooth {
|
.menu-dropdown-label.bluetooth {
|
||||||
color: #89dceb;
|
color: #89dceb;
|
||||||
@@ -1012,7 +1040,7 @@ image {
|
|||||||
min-height: 6em;
|
min-height: 6em;
|
||||||
background: #11111b;
|
background: #11111b;
|
||||||
border: 0.13em solid #313244;
|
border: 0.13em solid #313244;
|
||||||
border-radius: 0.4em;
|
border-radius: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-content.notificationsmenu-window {
|
.window-content.notificationsmenu-window {
|
||||||
@@ -1084,7 +1112,7 @@ image {
|
|||||||
min-height: 6em;
|
min-height: 6em;
|
||||||
background: #11111b;
|
background: #11111b;
|
||||||
border: 0.13em solid #313244;
|
border: 0.13em solid #313244;
|
||||||
border-radius: 0.4em;
|
border-radius: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-content.calendarmenu-window {
|
.window-content.calendarmenu-window {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user